diff --git a/Application/API/GameLogServer/IGameLogServer.cs b/Application/API/GameLogServer/IGameLogServer.cs index 302c9040..a0eb960b 100644 --- a/Application/API/GameLogServer/IGameLogServer.cs +++ b/Application/API/GameLogServer/IGameLogServer.cs @@ -1,12 +1,12 @@ using System.Threading.Tasks; -using RestEase; +using Refit; namespace IW4MAdmin.Application.API.GameLogServer { - [Header("User-Agent", "IW4MAdmin-RestEase")] + [Headers("User-Agent: IW4MAdmin-RestEase")] public interface IGameLogServer { - [Get("log/{path}/{key}")] - Task Log([Path] string path, [Path] string key); + [Get("/log/{path}/{key}")] + Task Log(string path, string key); } } diff --git a/Application/API/GameLogServer/LogInfo.cs b/Application/API/GameLogServer/LogInfo.cs index 612d4cdc..0286d096 100644 --- a/Application/API/GameLogServer/LogInfo.cs +++ b/Application/API/GameLogServer/LogInfo.cs @@ -1,19 +1,16 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Text; +using System.Text.Json.Serialization; namespace IW4MAdmin.Application.API.GameLogServer { public class LogInfo { - [JsonProperty("success")] + [JsonPropertyName("success")] public bool Success { get; set; } - [JsonProperty("length")] + [JsonPropertyName("length")] public int Length { get; set; } - [JsonProperty("data")] + [JsonPropertyName("data")] public string Data { get; set; } - [JsonProperty("next_key")] + [JsonPropertyName("next_key")] public string NextKey { get; set; } } } diff --git a/Application/API/Master/ApiInstance.cs b/Application/API/Master/ApiInstance.cs index 01a98baf..c70fdca4 100644 --- a/Application/API/Master/ApiInstance.cs +++ b/Application/API/Master/ApiInstance.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; using SharedLibraryCore.Helpers; namespace IW4MAdmin.Application.API.Master @@ -12,32 +12,32 @@ namespace IW4MAdmin.Application.API.Master /// /// Unique ID of the instance /// - [JsonProperty("id")] + [JsonPropertyName("id")] public string Id { get; set; } /// /// Indicates how long the instance has been running /// - [JsonProperty("uptime")] + [JsonPropertyName("uptime")] public int Uptime { get; set; } /// /// Specifies the version of the instance /// - [JsonProperty("version")] + [JsonPropertyName("version")] [JsonConverter(typeof(BuildNumberJsonConverter))] public BuildNumber Version { get; set; } /// /// List of servers the instance is monitoring /// - [JsonProperty("servers")] + [JsonPropertyName("servers")] public List Servers { get; set; } /// /// Url IW4MAdmin is listening on /// - [JsonProperty("webfront_url")] + [JsonPropertyName("webfront_url")] public string WebfrontUrl { get; set; } } } diff --git a/Application/API/Master/ApiServer.cs b/Application/API/Master/ApiServer.cs index 123a5852..4c2fe3ca 100644 --- a/Application/API/Master/ApiServer.cs +++ b/Application/API/Master/ApiServer.cs @@ -1,31 +1,28 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Text; +using System.Text.Json.Serialization; namespace IW4MAdmin.Application.API.Master { public class ApiServer { - [JsonProperty("id")] + [JsonPropertyName("id")] public long Id { get; set; } - [JsonProperty("ip")] + [JsonPropertyName("ip")] public string IPAddress { get; set; } - [JsonProperty("port")] + [JsonPropertyName("port")] public short Port { get; set; } - [JsonProperty("version")] + [JsonPropertyName("version")] public string Version { get; set; } - [JsonProperty("gametype")] + [JsonPropertyName("gametype")] public string Gametype { get; set; } - [JsonProperty("map")] + [JsonPropertyName("map")] public string Map { get; set; } - [JsonProperty("game")] + [JsonPropertyName("game")] public string Game { get; set; } - [JsonProperty("hostname")] + [JsonPropertyName("hostname")] public string Hostname { get; set; } - [JsonProperty("clientnum")] + [JsonPropertyName("clientnum")] public int ClientNum { get; set; } - [JsonProperty("maxclientnum")] + [JsonPropertyName("maxclientnum")] public int MaxClientNum { get; set; } } } diff --git a/Application/API/Master/IMasterApi.cs b/Application/API/Master/IMasterApi.cs index c96689f7..5c628fc6 100644 --- a/Application/API/Master/IMasterApi.cs +++ b/Application/API/Master/IMasterApi.cs @@ -1,79 +1,70 @@ using System; using System.Collections.Generic; +using System.Text.Json.Serialization; using System.Threading.Tasks; using IW4MAdmin.Application.Plugin; -using Newtonsoft.Json; -using RestEase; +using Refit; using SharedLibraryCore.Helpers; -namespace IW4MAdmin.Application.API.Master +namespace IW4MAdmin.Application.API.Master; + +public class AuthenticationId { - public class AuthenticationId - { - [JsonProperty("id")] - public string Id { get; set; } - } - - public class TokenId - { - [JsonProperty("access_token")] - public string AccessToken { get; set; } - } - - public class VersionInfo - { - [JsonProperty("current-version-stable")] - [JsonConverter(typeof(BuildNumberJsonConverter))] - public BuildNumber CurrentVersionStable { get; set; } - - [JsonProperty("current-version-prerelease")] - [JsonConverter(typeof(BuildNumberJsonConverter))] - public BuildNumber CurrentVersionPrerelease { get; set; } - } - - public class ResultMessage - { - [JsonProperty("message")] - public string Message { get; set; } - } - - public class PluginSubscriptionContent - { - public string Content { get; set; } - public PluginType Type { get; set; } - } - - - /// - /// Defines the capabilities of the master API - /// - [Header("User-Agent", "IW4MAdmin-RestEase")] - public interface IMasterApi - { - [Header("Authorization")] - string AuthorizationToken { get; set; } - - [Post("authenticate")] - Task Authenticate([Body] AuthenticationId Id); - - [Post("instance/")] - [AllowAnyStatusCode] - Task> AddInstance([Body] ApiInstance instance); - - [Put("instance/{id}")] - [AllowAnyStatusCode] - Task> UpdateInstance([Path] string id, [Body] ApiInstance instance); - - [Get("version/{apiVersion}")] - Task GetVersion([Path] int apiVersion); - - [Get("localization")] - Task> GetLocalization(); - - [Get("localization/{languageTag}")] - Task GetLocalization([Path("languageTag")] string languageTag); - - [Get("plugin_subscriptions")] - Task> GetPluginSubscription([Query("instance_id")] Guid instanceId, [Query("subscription_id")] string subscription_id); - } + [JsonPropertyName("id")] public string Id { get; set; } +} + +public class TokenId +{ + [JsonPropertyName("access_token")] public string AccessToken { get; set; } +} + +public class VersionInfo +{ + [JsonPropertyName("current-version-stable")] + [JsonConverter(typeof(BuildNumberJsonConverter))] + public BuildNumber CurrentVersionStable { get; set; } + + [JsonPropertyName("current-version-prerelease")] + [JsonConverter(typeof(BuildNumberJsonConverter))] + public BuildNumber CurrentVersionPrerelease { get; set; } +} + +public class ResultMessage +{ + [JsonPropertyName("message")] public string Message { get; set; } +} + +public class PluginSubscriptionContent +{ + public string Content { get; set; } + public PluginType Type { get; set; } +} + +/// +/// Defines the capabilities of the master API +/// +[Headers("User-Agent: IW4MAdmin-RestEase")] +public interface IMasterApi +{ + [Post("/authenticate")] + Task Authenticate([Body] AuthenticationId Id); + + [Post("/instance/")] + Task> AddInstance([Body] ApiInstance instance, [Header("Authorization")] string authorization); + + [Put("/instance/{id}")] + Task> UpdateInstance(string id, [Body] ApiInstance instance, [Header("Authorization")] string authorization); + + [Get("/version/{apiVersion}")] + Task GetVersion(int apiVersion); + + [Get("/localization")] + Task> GetLocalization(); + + [Get("/localization/{languageTag}")] + Task GetLocalization(string languageTag); + + [Get("/plugin_subscriptions")] + Task> GetPluginSubscription([Query("instance_id")] Guid instanceId, + [Query("subscription_id")] string subscription_id); } diff --git a/Application/Application.csproj b/Application/Application.csproj index 858f10a5..1609bc45 100644 --- a/Application/Application.csproj +++ b/Application/Application.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net8.0 false RaidMax.IW4MAdmin.Application 2020.0.0.0 @@ -21,20 +21,21 @@ IW4MAdmin.Application false + disable - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - + diff --git a/Application/IO/GameLogEventDetection.cs b/Application/IO/GameLogEventDetection.cs index eca6fb8c..54b8b9f6 100644 --- a/Application/IO/GameLogEventDetection.cs +++ b/Application/IO/GameLogEventDetection.cs @@ -82,7 +82,7 @@ namespace IW4MAdmin.Application.IO { if ((gameEvent.RequiredEntity & GameEvent.EventRequiredEntity.Origin) == GameEvent.EventRequiredEntity.Origin && gameEvent.Origin.NetworkId != Utilities.WORLD_ID) { - gameEvent.Origin = _server.GetClientsAsList().First(_client => _client.NetworkId == gameEvent.Origin?.NetworkId);; + gameEvent.Origin = _server.GetClientsAsList().First(_client => _client.NetworkId == gameEvent.Origin?.NetworkId); } if ((gameEvent.RequiredEntity & GameEvent.EventRequiredEntity.Target) == GameEvent.EventRequiredEntity.Target) diff --git a/Application/IO/GameLogReaderHttp.cs b/Application/IO/GameLogReaderHttp.cs index a585fa89..16a4437d 100644 --- a/Application/IO/GameLogReaderHttp.cs +++ b/Application/IO/GameLogReaderHttp.cs @@ -1,5 +1,4 @@ using IW4MAdmin.Application.API.GameLogServer; -using RestEase; using SharedLibraryCore; using SharedLibraryCore.Interfaces; using System; @@ -7,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Refit; using ILogger = Microsoft.Extensions.Logging.ILogger; namespace IW4MAdmin.Application.IO @@ -25,7 +25,7 @@ namespace IW4MAdmin.Application.IO public GameLogReaderHttp(Uri[] gameLogServerUris, IEventParser parser, ILogger logger) { _eventParser = parser; - _logServerApi = RestClient.For(gameLogServerUris[0].ToString()); + _logServerApi = RestService.For(gameLogServerUris[0].ToString()); _safeLogPath = gameLogServerUris[1].LocalPath.ToBase64UrlSafeString(); _logger = logger; } diff --git a/Application/Localization/Configure.cs b/Application/Localization/Configure.cs index b2155e97..abe5b731 100644 --- a/Application/Localization/Configure.cs +++ b/Application/Localization/Configure.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Text; +using System.Text.Json; using Microsoft.Extensions.Logging; using SharedLibraryCore.Configuration; using ILogger = Microsoft.Extensions.Logging.ILogger; @@ -59,11 +60,11 @@ namespace IW4MAdmin.Application.Localization var localizationDict = new Dictionary(); - foreach (string filePath in localizationFiles) + foreach (var filePath in localizationFiles) { var localizationContents = File.ReadAllText(filePath, Encoding.UTF8); - var eachLocalizationFile = Newtonsoft.Json.JsonConvert.DeserializeObject(localizationContents); - if (eachLocalizationFile == null) + var eachLocalizationFile = JsonSerializer.Deserialize(localizationContents); + if (eachLocalizationFile is null) { continue; } @@ -72,7 +73,7 @@ namespace IW4MAdmin.Application.Localization { if (!localizationDict.TryAdd(item.Key, item.Value)) { - logger.LogError("Could not add locale string {key} to localization", item.Key); + logger.LogError("Could not add locale string {Key} to localization", item.Key); } } } diff --git a/Application/Main.cs b/Application/Main.cs index bcded032..d4c3e62b 100644 --- a/Application/Main.cs +++ b/Application/Main.cs @@ -5,7 +5,6 @@ using IW4MAdmin.Application.Meta; using IW4MAdmin.Application.Migration; using IW4MAdmin.Application.Misc; using Microsoft.Extensions.DependencyInjection; -using RestEase; using SharedLibraryCore; using SharedLibraryCore.Configuration; using SharedLibraryCore.Database.Models; @@ -39,6 +38,7 @@ using ILogger = Microsoft.Extensions.Logging.ILogger; using IW4MAdmin.Plugins.Stats.Client.Abstractions; using IW4MAdmin.Plugins.Stats.Client; using Microsoft.Extensions.Hosting; +using Refit; using Stats.Client.Abstractions; using Stats.Client; using Stats.Config; @@ -94,15 +94,6 @@ namespace IW4MAdmin.Application Console.WriteLine($" Version {Utilities.GetVersionAsString()}"); Console.WriteLine("====================================================="); - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("!!!! IMPORTANT !!!!"); - Console.WriteLine("The next update of IW4MAdmin will require .NET 8."); - Console.WriteLine("This is a breaking change!"); - Console.WriteLine( - "Please update the ASP.NET Core Runtime: https://dotnet.microsoft.com/en-us/download/dotnet/8.0"); - Console.WriteLine("!!!!!!!!!!!!!!!!!!!"); - Console.ForegroundColor = ConsoleColor.Gray; - await LaunchAsync(); } @@ -451,12 +442,12 @@ namespace IW4MAdmin.Application var masterUri = Utilities.IsDevelopment ? new Uri("http://127.0.0.1:8080") : appConfig?.MasterUrl ?? new ApplicationConfiguration().MasterUrl; - var httpClient = new HttpClient + var httpClient = new HttpClient(new HttpClientHandler {AllowAutoRedirect = true}) { BaseAddress = masterUri, Timeout = TimeSpan.FromSeconds(15) }; - var masterRestClient = RestClient.For(httpClient); + var masterRestClient = RestService.For(httpClient); var translationLookup = Configure.Initialize(Utilities.DefaultLogger, masterRestClient, appConfig); if (appConfig == null) @@ -469,10 +460,7 @@ namespace IW4MAdmin.Application // register override level names foreach (var (key, value) in appConfig.OverridePermissionLevelNames) { - if (!Utilities.PermissionLevelOverrides.ContainsKey(key)) - { - Utilities.PermissionLevelOverrides.Add(key, value); - } + Utilities.PermissionLevelOverrides.TryAdd(key, value); } // build the dependency list diff --git a/Application/Misc/MasterCommunication.cs b/Application/Misc/MasterCommunication.cs index 76fc0904..86adc1a6 100644 --- a/Application/Misc/MasterCommunication.cs +++ b/Application/Misc/MasterCommunication.cs @@ -1,5 +1,4 @@ using IW4MAdmin.Application.API.Master; -using RestEase; using SharedLibraryCore; using SharedLibraryCore.Configuration; using SharedLibraryCore.Helpers; @@ -9,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Refit; using ILogger = Microsoft.Extensions.Logging.ILogger; namespace IW4MAdmin.Application.Misc @@ -28,6 +28,7 @@ namespace IW4MAdmin.Application.Misc private readonly int _apiVersion = 1; private bool _firstHeartBeat = true; private static readonly TimeSpan Interval = TimeSpan.FromSeconds(30); + private string _authorizationToken; public MasterCommunication(ILogger logger, ApplicationConfiguration appConfig, ITranslationLookup translationLookup, IMasterApi apiInstance, IManager manager) { @@ -128,7 +129,7 @@ namespace IW4MAdmin.Application.Misc Id = _appConfig.Id }); - _apiInstance.AuthorizationToken = $"Bearer {token.AccessToken}"; + _authorizationToken = $"Bearer {token.AccessToken}"; } var instance = new ApiInstance @@ -153,22 +154,22 @@ namespace IW4MAdmin.Application.Misc WebfrontUrl = _appConfig.WebfrontUrl }; - Response response; + IApiResponse response; if (_firstHeartBeat) { - response = await _apiInstance.AddInstance(instance); + response = await _apiInstance.AddInstance(instance, _authorizationToken); } else { - response = await _apiInstance.UpdateInstance(instance.Id, instance); + response = await _apiInstance.UpdateInstance(instance.Id, instance, _authorizationToken); _firstHeartBeat = false; } - if (response.ResponseMessage.StatusCode != System.Net.HttpStatusCode.OK) + if (response.StatusCode != System.Net.HttpStatusCode.OK) { - _logger.LogWarning("Non success response code from master is {StatusCode}, message is {Message}", response.ResponseMessage.StatusCode, response.StringContent); + _logger.LogWarning("Non success response code from master is {StatusCode}, message is {Message}", response.StatusCode, response.Error?.Content); } } } diff --git a/Application/Misc/SerializationHelpers.cs b/Application/Misc/SerializationHelpers.cs index bfb7e0b9..9d8a5f03 100644 --- a/Application/Misc/SerializationHelpers.cs +++ b/Application/Misc/SerializationHelpers.cs @@ -1,150 +1,255 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using SharedLibraryCore; +using SharedLibraryCore; using SharedLibraryCore.Database.Models; using System; using System.Net; +using System.Text.Json; +using System.Text.Json.Serialization; using Data.Models; using static SharedLibraryCore.Database.Models.EFClient; using static SharedLibraryCore.GameEvent; -namespace IW4MAdmin.Application.Misc +namespace IW4MAdmin.Application.Misc; + +public class IPAddressConverter : JsonConverter { - class IPAddressConverter : JsonConverter + public override IPAddress Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - public override bool CanConvert(Type objectType) - { - return (objectType == typeof(IPAddress)); - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - writer.WriteValue(value.ToString()); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - return IPAddress.Parse((string)reader.Value); - } + var ipAddressString = reader.GetString(); + return IPAddress.Parse(ipAddressString); } - class IPEndPointConverter : JsonConverter + public override void Write(Utf8JsonWriter writer, IPAddress value, JsonSerializerOptions options) { - public override bool CanConvert(Type objectType) - { - return (objectType == typeof(IPEndPoint)); - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - IPEndPoint ep = (IPEndPoint)value; - JObject jo = new JObject(); - jo.Add("Address", JToken.FromObject(ep.Address, serializer)); - jo.Add("Port", ep.Port); - jo.WriteTo(writer); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - JObject jo = JObject.Load(reader); - IPAddress address = jo["Address"].ToObject(serializer); - int port = (int)jo["Port"]; - return new IPEndPoint(address, port); - } - } - - class ClientEntityConverter : JsonConverter - { - public override bool CanConvert(Type objectType) => objectType == typeof(EFClient); - - public override object ReadJson(JsonReader reader, Type objectType,object existingValue, JsonSerializer serializer) - { - if (reader.Value == null) - { - return null; - } - - var jsonObject = JObject.Load(reader); - - return new EFClient - { - NetworkId = (long)jsonObject["NetworkId"], - ClientNumber = (int)jsonObject["ClientNumber"], - State = Enum.Parse(jsonObject["state"].ToString()), - CurrentAlias = new EFAlias() - { - IPAddress = (int?)jsonObject["IPAddress"], - Name = jsonObject["Name"].ToString() - } - }; - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var client = value as EFClient; - var jsonObject = new JObject - { - { "NetworkId", client.NetworkId }, - { "ClientNumber", client.ClientNumber }, - { "IPAddress", client.CurrentAlias?.IPAddress }, - { "Name", client.CurrentAlias?.Name }, - { "State", (int)client.State } - }; - - jsonObject.WriteTo(writer); - } - } - - class GameEventConverter : JsonConverter - { - public override bool CanConvert(Type objectType) =>objectType == typeof(GameEvent); - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - var jsonObject = JObject.Load(reader); - - return new GameEvent - { - Type = Enum.Parse(jsonObject["Type"].ToString()), - Subtype = jsonObject["Subtype"]?.ToString(), - Source = Enum.Parse(jsonObject["Source"].ToString()), - RequiredEntity = Enum.Parse(jsonObject["RequiredEntity"].ToString()), - Data = jsonObject["Data"].ToString(), - Message = jsonObject["Message"].ToString(), - GameTime = (int?)jsonObject["GameTime"], - Origin = jsonObject["Origin"]?.ToObject(serializer), - Target = jsonObject["Target"]?.ToObject(serializer), - ImpersonationOrigin = jsonObject["ImpersonationOrigin"]?.ToObject(serializer), - IsRemote = (bool)jsonObject["IsRemote"], - Extra = null, // fix - Time = (DateTime)jsonObject["Time"], - IsBlocking = (bool)jsonObject["IsBlocking"] - }; - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var gameEvent = value as GameEvent; - - var jsonObject = new JObject - { - { "Type", (int)gameEvent.Type }, - { "Subtype", gameEvent.Subtype }, - { "Source", (int)gameEvent.Source }, - { "RequiredEntity", (int)gameEvent.RequiredEntity }, - { "Data", gameEvent.Data }, - { "Message", gameEvent.Message }, - { "GameTime", gameEvent.GameTime }, - { "Origin", gameEvent.Origin != null ? JToken.FromObject(gameEvent.Origin, serializer) : null }, - { "Target", gameEvent.Target != null ? JToken.FromObject(gameEvent.Target, serializer) : null }, - { "ImpersonationOrigin", gameEvent.ImpersonationOrigin != null ? JToken.FromObject(gameEvent.ImpersonationOrigin, serializer) : null}, - { "IsRemote", gameEvent.IsRemote }, - { "Extra", gameEvent.Extra?.ToString() }, - { "Time", gameEvent.Time }, - { "IsBlocking", gameEvent.IsBlocking } - }; - - jsonObject.WriteTo(writer); - } + writer.WriteStringValue(value.ToString()); + } +} + +public class IPEndPointConverter : JsonConverter +{ + public override IPEndPoint Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + IPAddress address = null; + var port = 0; + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.PropertyName) + { + var propertyName = reader.GetString(); + reader.Read(); + switch (propertyName) + { + case "Address": + var addressString = reader.GetString(); + address = IPAddress.Parse(addressString); + break; + case "Port": + port = reader.GetInt32(); + break; + } + } + + if (reader.TokenType == JsonTokenType.EndObject) + { + break; + } + } + + return new IPEndPoint(address, port); + } + + public override void Write(Utf8JsonWriter writer, IPEndPoint value, JsonSerializerOptions options) + { + writer.WriteStartObject(); + writer.WriteString("Address", value.Address.ToString()); + writer.WriteNumber("Port", value.Port); + writer.WriteEndObject(); + } +} + +public class ClientEntityConverter : JsonConverter +{ + public override EFClient Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + long networkId = default; + int clientNumber = default; + ClientState state = default; + var currentAlias = new EFAlias(); + int? ipAddress = null; + string name = null; + + while (reader.Read() && reader.TokenType != JsonTokenType.EndObject) + { + if (reader.TokenType == JsonTokenType.PropertyName) + { + var propertyName = reader.GetString(); + reader.Read(); // Advance to the value. + switch (propertyName) + { + case "NetworkId": + networkId = reader.GetInt64(); + break; + case "ClientNumber": + clientNumber = reader.GetInt32(); + break; + case "State": + state = (ClientState)reader.GetInt32(); + break; + case "IPAddress": + ipAddress = reader.TokenType != JsonTokenType.Null ? reader.GetInt32() : null; + break; + case "Name": + name = reader.GetString(); + break; + } + } + } + + currentAlias.IPAddress = ipAddress; + currentAlias.Name = name; + + return new EFClient + { + NetworkId = networkId, + ClientNumber = clientNumber, + State = state, + CurrentAlias = currentAlias + }; + } + + public override void Write(Utf8JsonWriter writer, EFClient value, JsonSerializerOptions options) + { + writer.WriteStartObject(); + + writer.WriteNumber("NetworkId", value.NetworkId); + writer.WriteNumber("ClientNumber", value.ClientNumber); + writer.WriteString("State", value.State.ToString()); + + if (value.CurrentAlias != null) + { + writer.WriteNumber("IPAddress", value.CurrentAlias.IPAddress ?? 0); + writer.WriteString("Name", value.CurrentAlias.Name); + } + else + { + writer.WriteNull("IPAddress"); + writer.WriteNull("Name"); + } + + writer.WriteEndObject(); + } +} + +public class GameEventConverter : JsonConverter +{ + public override GameEvent Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + var gameEvent = new GameEvent(); + while (reader.Read() && reader.TokenType != JsonTokenType.EndObject) + { + if (reader.TokenType == JsonTokenType.PropertyName) + { + var propertyName = reader.GetString(); + reader.Read(); + switch (propertyName) + { + case "Type": + gameEvent.Type = (EventType)reader.GetInt32(); + break; + case "Subtype": + gameEvent.Subtype = reader.GetString(); + break; + case "Source": + gameEvent.Source = (EventSource)reader.GetInt32(); + break; + case "RequiredEntity": + gameEvent.RequiredEntity = (EventRequiredEntity)reader.GetInt32(); + break; + case "Data": + gameEvent.Data = reader.GetString(); + break; + case "Message": + gameEvent.Message = reader.GetString(); + break; + case "GameTime": + gameEvent.GameTime = reader.TokenType != JsonTokenType.Null ? reader.GetInt32() : null; + break; + case "Origin": + gameEvent.Origin = JsonSerializer.Deserialize(ref reader, options); + break; + case "Target": + gameEvent.Target = JsonSerializer.Deserialize(ref reader, options); + break; + case "ImpersonationOrigin": + gameEvent.ImpersonationOrigin = JsonSerializer.Deserialize(ref reader, options); + break; + case "IsRemote": + gameEvent.IsRemote = reader.GetBoolean(); + break; + case "Time": + gameEvent.Time = reader.GetDateTime(); + break; + case "IsBlocking": + gameEvent.IsBlocking = reader.GetBoolean(); + break; + } + } + } + + return gameEvent; + } + + public override void Write(Utf8JsonWriter writer, GameEvent value, JsonSerializerOptions options) + { + writer.WriteStartObject(); + + writer.WriteNumber("Type", (int)value.Type); + writer.WriteString("Subtype", value.Subtype); + writer.WriteNumber("Source", (int)value.Source); + writer.WriteNumber("RequiredEntity", (int)value.RequiredEntity); + writer.WriteString("Data", value.Data); + writer.WriteString("Message", value.Message); + if (value.GameTime.HasValue) + { + writer.WriteNumber("GameTime", value.GameTime.Value); + } + else + { + writer.WriteNull("GameTime"); + } + + if (value.Origin != null) + { + writer.WritePropertyName("Origin"); + JsonSerializer.Serialize(writer, value.Origin, options); + } + + if (value.Target != null) + { + writer.WritePropertyName("Target"); + JsonSerializer.Serialize(writer, value.Target, options); + } + + if (value.ImpersonationOrigin != null) + { + writer.WritePropertyName("ImpersonationOrigin"); + JsonSerializer.Serialize(writer, value.ImpersonationOrigin, options); + } + + writer.WriteBoolean("IsRemote", value.IsRemote); + writer.WriteString("Time", value.Time.ToString("o")); + writer.WriteBoolean("IsBlocking", value.IsBlocking); + + writer.WriteEndObject(); } } diff --git a/Application/Plugin/Script/ScriptPlugin.cs b/Application/Plugin/Script/ScriptPlugin.cs index b5da929f..49822c11 100644 --- a/Application/Plugin/Script/ScriptPlugin.cs +++ b/Application/Plugin/Script/ScriptPlugin.cs @@ -23,6 +23,7 @@ using SharedLibraryCore.Database.Models; using SharedLibraryCore.Exceptions; using SharedLibraryCore.Interfaces; using ILogger = Microsoft.Extensions.Logging.ILogger; +using Reference = Data.Models.Reference; namespace IW4MAdmin.Application.Plugin.Script { diff --git a/Application/Plugin/Script/ScriptPluginV2.cs b/Application/Plugin/Script/ScriptPluginV2.cs index 26edcaa2..8ac8b2a6 100644 --- a/Application/Plugin/Script/ScriptPluginV2.cs +++ b/Application/Plugin/Script/ScriptPluginV2.cs @@ -26,6 +26,7 @@ using SharedLibraryCore.Interfaces; using SharedLibraryCore.Interfaces.Events; using ILogger = Microsoft.Extensions.Logging.ILogger; using JavascriptEngine = Jint.Engine; +using Reference = Data.Models.Reference; namespace IW4MAdmin.Application.Plugin.Script; diff --git a/Data/Data.csproj b/Data/Data.csproj index 75cbf585..412a8aca 100644 --- a/Data/Data.csproj +++ b/Data/Data.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 Debug;Release;Prerelease AnyCPU RaidMax.IW4MAdmin.Data @@ -9,16 +9,20 @@ - - - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all runtime; build; native; contentfiles - - - - + + + + diff --git a/Integrations/Cod/Integrations.Cod.csproj b/Integrations/Cod/Integrations.Cod.csproj index 7d10e54a..de12b577 100644 --- a/Integrations/Cod/Integrations.Cod.csproj +++ b/Integrations/Cod/Integrations.Cod.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 Integrations.Cod Integrations.Cod Debug;Release;Prerelease @@ -17,7 +17,7 @@ - + diff --git a/Integrations/Source/Integrations.Source.csproj b/Integrations/Source/Integrations.Source.csproj index cd174636..b33da35b 100644 --- a/Integrations/Source/Integrations.Source.csproj +++ b/Integrations/Source/Integrations.Source.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 Integrations.Source Integrations.Source Debug;Release;Prerelease diff --git a/Plugins/AutomessageFeed/AutomessageFeed.csproj b/Plugins/AutomessageFeed/AutomessageFeed.csproj index 1a79d2e5..4a5a0ac7 100644 --- a/Plugins/AutomessageFeed/AutomessageFeed.csproj +++ b/Plugins/AutomessageFeed/AutomessageFeed.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 true Latest Debug;Release;Prerelease @@ -10,7 +10,7 @@ - + diff --git a/Plugins/LiveRadar/LiveRadar.csproj b/Plugins/LiveRadar/LiveRadar.csproj index a5a50206..a1630dfd 100644 --- a/Plugins/LiveRadar/LiveRadar.csproj +++ b/Plugins/LiveRadar/LiveRadar.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 true true false @@ -16,7 +16,7 @@ - + diff --git a/Plugins/Login/Login.csproj b/Plugins/Login/Login.csproj index b3a92171..2a48f854 100644 --- a/Plugins/Login/Login.csproj +++ b/Plugins/Login/Login.csproj @@ -2,7 +2,7 @@ Library - net6.0 + net8.0 false @@ -19,7 +19,7 @@ - + diff --git a/Plugins/Mute/Mute.csproj b/Plugins/Mute/Mute.csproj index 19e6bb03..cb66c4d4 100644 --- a/Plugins/Mute/Mute.csproj +++ b/Plugins/Mute/Mute.csproj @@ -1,18 +1,17 @@ - net6.0 + net8.0 enable enable MrAmos123 Library Debug;Release;Prerelease AnyCPU - IW4MAdmin.Plugins.Mute - + diff --git a/Plugins/Mute/Plugin.cs b/Plugins/Mute/Plugin.cs index fc75ea27..d1c36815 100644 --- a/Plugins/Mute/Plugin.cs +++ b/Plugins/Mute/Plugin.cs @@ -22,7 +22,7 @@ public class Plugin : IPluginV2 public const string MuteKey = "IW4MMute"; public static IManager Manager { get; private set; } = null!; public static Server.Game[] SupportedGames { get; private set; } = Array.Empty(); - private static readonly string[] DisabledCommands = {nameof(PrivateMessageAdminsCommand), "PrivateMessageCommand"}; + private static readonly string[] DisabledCommands = [nameof(PrivateMessageAdminsCommand), "PrivateMessageCommand"]; private readonly IInteractionRegistration _interactionRegistration; private readonly IRemoteCommandService _remoteCommandService; private readonly MuteManager _muteManager; @@ -37,6 +37,7 @@ public class Plugin : IPluginV2 IManagementEventSubscriptions.Load += OnLoad; IManagementEventSubscriptions.Unload += OnUnload; + IManagementEventSubscriptions.ClientStateInitialized += OnClientStateInitialized; IGameServerEventSubscriptions.ClientDataUpdated += OnClientDataUpdated; diff --git a/Plugins/ProfanityDeterment/ProfanityDeterment.csproj b/Plugins/ProfanityDeterment/ProfanityDeterment.csproj index 8334a992..9b3452fd 100644 --- a/Plugins/ProfanityDeterment/ProfanityDeterment.csproj +++ b/Plugins/ProfanityDeterment/ProfanityDeterment.csproj @@ -2,7 +2,7 @@ Library - net6.0 + net8.0 RaidMax.IW4MAdmin.Plugins.ProfanityDeterment @@ -16,7 +16,7 @@ - + diff --git a/Plugins/Stats/Stats.csproj b/Plugins/Stats/Stats.csproj index 7aff2f0c..7d65d949 100644 --- a/Plugins/Stats/Stats.csproj +++ b/Plugins/Stats/Stats.csproj @@ -2,7 +2,7 @@ Library - net6.0 + net8.0 RaidMax.IW4MAdmin.Plugins.Stats @@ -17,7 +17,7 @@ - + diff --git a/Plugins/Welcome/Plugin.cs b/Plugins/Welcome/Plugin.cs index e5189f11..30d43870 100644 --- a/Plugins/Welcome/Plugin.cs +++ b/Plugins/Welcome/Plugin.cs @@ -6,8 +6,8 @@ using SharedLibraryCore.Database.Models; using System.Linq; using Microsoft.EntityFrameworkCore; using System.Net.Http; +using System.Text.Json; using System.Threading; -using Newtonsoft.Json.Linq; using Humanizer; using Data.Abstractions; using Data.Models; @@ -108,8 +108,9 @@ public class Plugin : IPluginV2 var response = await wc.GetStringAsync(new Uri( $"http://ip-api.com/json/{ip}?lang={Utilities.CurrentLocalization.LocalizationName.Split("-").First().ToLower()}")); - var responseObj = JObject.Parse(response); - response = responseObj["country"]?.ToString(); + + var json = JsonDocument.Parse(response); + response = json.RootElement.TryGetProperty("country", out var countryElement) ? countryElement.GetString() : null; return string.IsNullOrEmpty(response) ? Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_UNKNOWN_COUNTRY"] diff --git a/Plugins/Welcome/Welcome.csproj b/Plugins/Welcome/Welcome.csproj index de9255ef..5e856f32 100644 --- a/Plugins/Welcome/Welcome.csproj +++ b/Plugins/Welcome/Welcome.csproj @@ -2,7 +2,7 @@ Library - net6.0 + net8.0 RaidMax.IW4MAdmin.Plugins.Welcome @@ -20,7 +20,7 @@ - + diff --git a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs index 4e5c9c16..092fa7e3 100644 --- a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs +++ b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Text.Json.Serialization; using Data.Models.Misc; -using Newtonsoft.Json; using SharedLibraryCore.Configuration.Attributes; using SharedLibraryCore.Interfaces; using static Data.Models.Client.EFClient; diff --git a/SharedLibraryCore/Configuration/CommandProperties.cs b/SharedLibraryCore/Configuration/CommandProperties.cs index da524910..e56c0e31 100644 --- a/SharedLibraryCore/Configuration/CommandProperties.cs +++ b/SharedLibraryCore/Configuration/CommandProperties.cs @@ -1,41 +1,40 @@ using System; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; +using System.Text.Json.Serialization; +using SharedLibraryCore.Helpers; using static Data.Models.Client.EFClient; using static SharedLibraryCore.Server; -namespace SharedLibraryCore.Configuration +namespace SharedLibraryCore.Configuration; + +/// +/// Config driven command properties +/// +public class CommandProperties { /// - /// Config driven command properties + /// Specifies the command name /// - public class CommandProperties - { - /// - /// Specifies the command name - /// - public string Name { get; set; } + public string Name { get; set; } - /// - /// Alias of this command - /// - public string Alias { get; set; } + /// + /// Alias of this command + /// + public string Alias { get; set; } - /// - /// Specifies the minimum permission level needed to execute the - /// - [JsonConverter(typeof(StringEnumConverter))] - public Permission MinimumPermission { get; set; } + /// + /// Specifies the minimum permission level needed to execute the + /// + [JsonConverter(typeof(JsonStringEnumConverter))] + public Permission MinimumPermission { get; set; } - /// - /// Indicates if the command can be run by another user (impersonation) - /// - public bool AllowImpersonation { get; set; } + /// + /// Indicates if the command can be run by another user (impersonation) + /// + public bool AllowImpersonation { get; set; } - /// - /// Specifies the games supporting the functionality of the command - /// - [JsonProperty(ItemConverterType = typeof(StringEnumConverter))] - public Game[] SupportedGames { get; set; } = Array.Empty(); - } + /// + /// Specifies the games supporting the functionality of the command + /// + [JsonConverter(typeof(GameArrayJsonConverter))] + public Game[] SupportedGames { get; set; } = Array.Empty(); } diff --git a/SharedLibraryCore/Events/CoreEvent.cs b/SharedLibraryCore/Events/CoreEvent.cs index 17d44b49..1891d64e 100644 --- a/SharedLibraryCore/Events/CoreEvent.cs +++ b/SharedLibraryCore/Events/CoreEvent.cs @@ -6,7 +6,7 @@ public abstract class CoreEvent { public Guid Id { get; } = Guid.NewGuid(); public Guid? CorrelationId { get; init; } - public object Source { get; init; } + public object Source { get; set; } public DateTimeOffset CreatedAt { get; } = DateTimeOffset.UtcNow; public DateTimeOffset? ProcessedAt { get; set; } } diff --git a/SharedLibraryCore/Helpers/BuildNumberJsonConverter.cs b/SharedLibraryCore/Helpers/BuildNumberJsonConverter.cs index cdac5943..a5aae46a 100644 --- a/SharedLibraryCore/Helpers/BuildNumberJsonConverter.cs +++ b/SharedLibraryCore/Helpers/BuildNumberJsonConverter.cs @@ -1,27 +1,58 @@ using System; -using Newtonsoft.Json; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; -namespace SharedLibraryCore.Helpers +namespace SharedLibraryCore.Helpers; + +/// +/// JSON converter for the build number +/// +public class BuildNumberJsonConverter : JsonConverter { - /// - /// JSON converter for the build number - /// - public class BuildNumberJsonConverter : JsonConverter + public override BuildNumber Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - public override bool CanConvert(Type objectType) - { - return objectType == typeof(string); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, - JsonSerializer serializer) - { - return BuildNumber.Parse(reader.Value.ToString()); - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - writer.WriteValue(value.ToString()); - } + var stringValue = reader.GetString(); + return BuildNumber.Parse(stringValue); } -} \ No newline at end of file + + public override void Write(Utf8JsonWriter writer, BuildNumber value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString()); + } +} + +public class GameArrayJsonConverter : JsonConverter +{ + public override Server.Game[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + List games = []; + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndArray) + { + break; + } + + var gameString = reader.GetString(); + var game = Enum.Parse(gameString); + games.Add(game); + } + + return games.ToArray(); + } + + public override void Write(Utf8JsonWriter writer, Server.Game[] value, JsonSerializerOptions options) + { + writer.WriteStartArray(); + + foreach (var game in value) + { + writer.WriteStringValue(game.ToString()); + } + + writer.WriteEndArray(); + } +} + diff --git a/SharedLibraryCore/Interfaces/IGameServer.cs b/SharedLibraryCore/Interfaces/IGameServer.cs index e28bd2b1..6ae70bdf 100644 --- a/SharedLibraryCore/Interfaces/IGameServer.cs +++ b/SharedLibraryCore/Interfaces/IGameServer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Net; using System.Threading; using System.Threading.Tasks; using Data.Models; @@ -19,6 +20,9 @@ namespace SharedLibraryCore.Interfaces /// Task Kick(string reason, EFClient target, EFClient origin, EFPenalty previousPenalty = null); + IPEndPoint ResolvedIpEndPoint { get; } + IRConParser RconParser { get; } + /// /// Execute a server command /// @@ -35,72 +39,72 @@ namespace SharedLibraryCore.Interfaces /// /// Task SetDvarAsync(string name, object value, CancellationToken token = default); - + /// /// Time the most recent match ended /// DateTime? MatchEndTime { get; } - + /// /// Time the current match started /// DateTime? MatchStartTime { get; } - + /// /// List of connected clients /// IReadOnlyList ConnectedClients { get; } - + /// /// Game code corresponding to the development studio project /// Reference.Game GameCode { get; } - + /// /// Indicates if the anticheat/custom callbacks/live radar integration is enabled /// bool IsLegacyGameIntegrationEnabled { get; } - + /// /// Unique identifier for the server (typically ip:port) /// string Id { get; } - + /// /// Network address the server is listening on /// string ListenAddress { get; } - + /// /// Network port the server is listening on /// int ListenPort { get; } - + /// /// Name of the server (hostname) /// string ServerName { get; } - + /// /// Current gametype /// string Gametype { get; } - + /// /// Game password (required to join) /// string GamePassword { get; } - + /// /// Number of private client slots /// int PrivateClientSlots { get; } - + /// /// Current map the game server is running /// Map Map { get; } - + /// /// Database id for EFServer table and references /// diff --git a/SharedLibraryCore/Interfaces/IManager.cs b/SharedLibraryCore/Interfaces/IManager.cs index 3f0b4c6e..8805f939 100644 --- a/SharedLibraryCore/Interfaces/IManager.cs +++ b/SharedLibraryCore/Interfaces/IManager.cs @@ -41,6 +41,7 @@ namespace SharedLibraryCore.Interfaces ILogger GetLogger(long serverId); IList GetServers(); + List Servers { get; } IList GetCommands(); IList GetMessageTokens(); IList GetActiveClients(); diff --git a/SharedLibraryCore/Interfaces/IRConParser.cs b/SharedLibraryCore/Interfaces/IRConParser.cs index deee71d6..6316276d 100644 --- a/SharedLibraryCore/Interfaces/IRConParser.cs +++ b/SharedLibraryCore/Interfaces/IRConParser.cs @@ -15,35 +15,35 @@ namespace SharedLibraryCore.Interfaces /// /// stores the game/client specific version (usually the value of the "version" DVAR) /// - string Version { get; } + string Version { get; set; } /// /// specifies the game name (usually the internal studio iteration ie: IW4, T5 etc...) /// - Game GameName { get; } + Game GameName { get; set; } /// /// indicates if the game supports generating a log path from DVAR retrieval /// of fs_game, fs_basepath, g_log /// - bool CanGenerateLogPath { get; } + bool CanGenerateLogPath { get; set; } /// /// specifies the name of the parser /// - string Name { get; } + string Name { get; set; } /// /// specifies the type of rcon engine /// eg: COD, Source /// - string RConEngine { get; } + string RConEngine { get; set; } /// /// indicates that the game does not log to the mods folder (when mod is loaded), /// but rather always to the fs_basegame directory /// - bool IsOneLog { get; } + bool IsOneLog { get; set; } /// /// retrieves the value of a given DVAR @@ -54,7 +54,8 @@ namespace SharedLibraryCore.Interfaces /// default value to return if dvar retrieval fails /// /// - Task> GetDvarAsync(IRConConnection connection, string dvarName, T fallbackValue = default, CancellationToken token = default); + Task> GetDvarAsync(IRConConnection connection, string dvarName, T fallbackValue = default, + CancellationToken token = default); /// /// set value of DVAR by name @@ -65,7 +66,7 @@ namespace SharedLibraryCore.Interfaces /// /// Task SetDvarAsync(IRConConnection connection, string dvarName, object dvarValue, CancellationToken token = default); - + /// /// executes a console command on the server /// diff --git a/SharedLibraryCore/Interfaces/IRConParserConfiguration.cs b/SharedLibraryCore/Interfaces/IRConParserConfiguration.cs index f3da4b2c..c6473199 100644 --- a/SharedLibraryCore/Interfaces/IRConParserConfiguration.cs +++ b/SharedLibraryCore/Interfaces/IRConParserConfiguration.cs @@ -10,74 +10,74 @@ namespace SharedLibraryCore.Interfaces /// /// stores the command format for console commands /// - CommandPrefix CommandPrefixes { get; } + CommandPrefix CommandPrefixes { get; set; } /// /// stores the regex info for parsing get status response /// - ParserRegex Status { get; } + ParserRegex Status { get; set; } /// /// stores regex info for parsing the map line from rcon status response /// - ParserRegex MapStatus { get; } + ParserRegex MapStatus { get; set; } /// /// stores regex info for parsing the gametype line from rcon status response /// - ParserRegex GametypeStatus { get; } + ParserRegex GametypeStatus { get; set; } /// /// stores regex info for parsing hostname line from rcon status response /// - ParserRegex HostnameStatus { get; } + ParserRegex HostnameStatus { get; set; } /// /// stores regex info for parsing max players line from rcon status response /// - ParserRegex MaxPlayersStatus { get; } + ParserRegex MaxPlayersStatus { get; set; } /// /// stores the regex info for parsing get DVAR responses /// - ParserRegex Dvar { get; } + ParserRegex Dvar { get; set; } /// /// stores the regex info for parsing the header of a status response /// - ParserRegex StatusHeader { get; } + ParserRegex StatusHeader { get; set; } /// /// Specifies the expected response message from rcon when the server is not running /// - string ServerNotRunningResponse { get; } + string ServerNotRunningResponse { get; set; } /// /// indicates if the application should wait for response from server /// when executing a command /// - bool WaitForResponse { get; } + bool WaitForResponse { get; set; } /// /// indicates the format expected for parsed guids /// - NumberStyles GuidNumberStyle { get; } + NumberStyles GuidNumberStyle { get; set; } /// /// specifies simple mappings for dvar names in scenarios where the needed /// information is not stored in a traditional dvar name /// - IDictionary OverrideDvarNameMapping { get; } + IDictionary OverrideDvarNameMapping { get; set; } /// /// specifies the default dvar values for games that don't support certain dvars /// - IDictionary DefaultDvarValues { get; } + IDictionary DefaultDvarValues { get; set; } /// /// contains a setup of commands that have override timeouts /// - IDictionary OverrideCommandTimeouts { get; } + IDictionary OverrideCommandTimeouts { get; set; } /// /// specifies how many lines can be used for ingame notice @@ -87,29 +87,30 @@ namespace SharedLibraryCore.Interfaces /// /// specifies how many characters can be displayed per notice line /// - int NoticeMaxCharactersPerLine { get; } + int NoticeMaxCharactersPerLine { get; set; } /// /// specifies the characters used to split a line /// - string NoticeLineSeparator { get; } + string NoticeLineSeparator { get; set; } /// /// Default port the game listens to RCon requests on /// - int? DefaultRConPort { get; } + int? DefaultRConPort { get; set; } /// /// Default Indicator of where the game is installed (ex file path or registry entry) /// - string DefaultInstallationDirectoryHint { get; } + string DefaultInstallationDirectoryHint { get; set; } - ColorCodeMapping ColorCodeMapping { get; } + ColorCodeMapping ColorCodeMapping { get; set; } + + short FloodProtectInterval { get; set; } - short FloodProtectInterval { get; } /// /// indicates if diacritics (accented characters) should be normalized /// - bool ShouldRemoveDiacritics { get; } + bool ShouldRemoveDiacritics { get; set; } } } diff --git a/SharedLibraryCore/Localization/Layout.cs b/SharedLibraryCore/Localization/Layout.cs index a4b330e7..c7f58bb6 100644 --- a/SharedLibraryCore/Localization/Layout.cs +++ b/SharedLibraryCore/Localization/Layout.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Globalization; +using System.Text.Json.Serialization; using SharedLibraryCore.Interfaces; namespace SharedLibraryCore.Localization @@ -8,6 +9,8 @@ namespace SharedLibraryCore.Localization { private string localizationName; + public Layout() { } + public Layout(Dictionary set) { LocalizationIndex = new TranslationLookup @@ -27,7 +30,7 @@ namespace SharedLibraryCore.Localization } public TranslationLookup LocalizationIndex { get; set; } - public CultureInfo Culture { get; private set; } + [JsonIgnore] public CultureInfo Culture { get; private set; } } public class TranslationLookup : ITranslationLookup @@ -47,4 +50,4 @@ namespace SharedLibraryCore.Localization } } } -} \ No newline at end of file +} diff --git a/SharedLibraryCore/SharedLibraryCore.csproj b/SharedLibraryCore/SharedLibraryCore.csproj index 081458e6..d77a87a6 100644 --- a/SharedLibraryCore/SharedLibraryCore.csproj +++ b/SharedLibraryCore/SharedLibraryCore.csproj @@ -2,9 +2,9 @@ Library - net6.0 + net8.0 RaidMax.IW4MAdmin.SharedLibraryCore - 2023.4.5.1 + 2024.01.01.1 RaidMax Forever None Debug;Release;Prerelease @@ -19,7 +19,7 @@ true MIT Shared Library for IW4MAdmin - 2023.4.5.1 + 2024.01.01.1 true $(NoWarn);1591 @@ -34,31 +34,30 @@ - + - - - - - - - - - - + + + + + + + + + - - true - Data.dll - + + true + Data.dll + diff --git a/WebfrontCore/Controllers/ConfigurationController.cs b/WebfrontCore/Controllers/ConfigurationController.cs index 784f3703..876c49e5 100644 --- a/WebfrontCore/Controllers/ConfigurationController.cs +++ b/WebfrontCore/Controllers/ConfigurationController.cs @@ -10,10 +10,9 @@ using SharedLibraryCore.Interfaces; using System.Linq; using System.Reflection; using System.Text; +using System.Text.Json; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using WebfrontCore.ViewModels; namespace WebfrontCore.Controllers @@ -92,15 +91,15 @@ namespace WebfrontCore.Controllers try { - var file = JObject.Parse(content); + var jsonDocument = JsonDocument.Parse(content); } - catch (JsonReaderException ex) + catch (JsonException ex) { return BadRequest($"{fileName}: {ex.Message}"); } - var path = System.IO.Path.Join(Utilities.OperatingDirectory, "Configuration", - fileName.Replace($"{System.IO.Path.DirectorySeparatorChar}", "")); + var path = Path.Join(Utilities.OperatingDirectory, "Configuration", + fileName.Replace($"{Path.DirectorySeparatorChar}", "")); // todo: move into a service at some point if (!System.IO.File.Exists(path)) diff --git a/WebfrontCore/WebfrontCore.csproj b/WebfrontCore/WebfrontCore.csproj index 8ce9eb47..b8502413 100644 --- a/WebfrontCore/WebfrontCore.csproj +++ b/WebfrontCore/WebfrontCore.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 true true true @@ -46,9 +46,9 @@ - - - + + +