1
0
mirror of https://github.com/RaidMax/IW4M-Admin.git synced 2025-06-07 21:58:06 -05:00

Update projects to .net 8 (#326)

* Update codebase to target .NET 8.0 and improve JSON serialization

This commit switches our target framework from .NET 6.0 to .NET 8.0 and replaces Newtonsoft.Json with System.Text.Json for serialization. The JsonConverter classes have been updated to support the new JSON model and some enhancements were applied to the codebase such as fixing a command property and updating various package references.

* Align with Develop

* Update SharedLibraryCore package version

The version of the SharedLibraryCore package reference has been updated across multiple projects from '2024.2.4.85' to '2024.2.5.9'. Meanwhile, version within SharedLibraryCore.csproj has been changed from '2024.02.04.085' to '2024.01.01.1'. Changes also include removal of .NET 8 requirement notice and reenabling of status upload to master communicator.

* Update properties in IRConParser and IRConParserConfiguration to be settable

The properties in the `IRConParser` and `IRConParserConfiguration` interfaces were updated to include setters. Previously, the properties in these interfaces were read-only. This change allows for the modifications and extensions of properties defined, thereby bolstering flexibility for the handling of games and parsers.

* Replace RestEase with Refit in API usage

Refit has been implemented as a replacement for RestEase in all API calls. As such, all related code, parameters and imports have been adjusted to function with Refit. Logic has also been added to handle certain Refit-specific behaviours. Occurrences of the RestEase package have been removed from the project.

* Enable auto-redirect in HttpClient

The HttpClient instance used in Application/Main.cs has been modified to automatically follow redirect responses. This was accomplished by adding "AllowAutoRedirect = true" to the HttpClientHandler used when creating the HttpClient.

---------

Co-authored-by: Amos <amos2580@hotmail.co.uk>
This commit is contained in:
RaidMax 2024-06-22 10:19:06 -05:00 committed by GitHub
parent 1f82596582
commit 34af7a332c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 558 additions and 432 deletions

View File

@ -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<LogInfo> Log([Path] string path, [Path] string key);
[Get("/log/{path}/{key}")]
Task<LogInfo> Log(string path, string key);
}
}

View File

@ -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; }
}
}

View File

@ -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
/// <summary>
/// Unique ID of the instance
/// </summary>
[JsonProperty("id")]
[JsonPropertyName("id")]
public string Id { get; set; }
/// <summary>
/// Indicates how long the instance has been running
/// </summary>
[JsonProperty("uptime")]
[JsonPropertyName("uptime")]
public int Uptime { get; set; }
/// <summary>
/// Specifies the version of the instance
/// </summary>
[JsonProperty("version")]
[JsonPropertyName("version")]
[JsonConverter(typeof(BuildNumberJsonConverter))]
public BuildNumber Version { get; set; }
/// <summary>
/// List of servers the instance is monitoring
/// </summary>
[JsonProperty("servers")]
[JsonPropertyName("servers")]
public List<ApiServer> Servers { get; set; }
/// <summary>
/// Url IW4MAdmin is listening on
/// </summary>
[JsonProperty("webfront_url")]
[JsonPropertyName("webfront_url")]
public string WebfrontUrl { get; set; }
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
/// <summary>
/// Defines the capabilities of the master API
/// </summary>
[Header("User-Agent", "IW4MAdmin-RestEase")]
public interface IMasterApi
{
[Header("Authorization")]
string AuthorizationToken { get; set; }
[Post("authenticate")]
Task<TokenId> Authenticate([Body] AuthenticationId Id);
[Post("instance/")]
[AllowAnyStatusCode]
Task<Response<ResultMessage>> AddInstance([Body] ApiInstance instance);
[Put("instance/{id}")]
[AllowAnyStatusCode]
Task<Response<ResultMessage>> UpdateInstance([Path] string id, [Body] ApiInstance instance);
[Get("version/{apiVersion}")]
Task<VersionInfo> GetVersion([Path] int apiVersion);
[Get("localization")]
Task<List<SharedLibraryCore.Localization.Layout>> GetLocalization();
[Get("localization/{languageTag}")]
Task<SharedLibraryCore.Localization.Layout> GetLocalization([Path("languageTag")] string languageTag);
[Get("plugin_subscriptions")]
Task<IEnumerable<PluginSubscriptionContent>> 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; }
}
/// <summary>
/// Defines the capabilities of the master API
/// </summary>
[Headers("User-Agent: IW4MAdmin-RestEase")]
public interface IMasterApi
{
[Post("/authenticate")]
Task<TokenId> Authenticate([Body] AuthenticationId Id);
[Post("/instance/")]
Task<IApiResponse<ResultMessage>> AddInstance([Body] ApiInstance instance, [Header("Authorization")] string authorization);
[Put("/instance/{id}")]
Task<IApiResponse<ResultMessage>> UpdateInstance(string id, [Body] ApiInstance instance, [Header("Authorization")] string authorization);
[Get("/version/{apiVersion}")]
Task<VersionInfo> GetVersion(int apiVersion);
[Get("/localization")]
Task<List<SharedLibraryCore.Localization.Layout>> GetLocalization();
[Get("/localization/{languageTag}")]
Task<SharedLibraryCore.Localization.Layout> GetLocalization(string languageTag);
[Get("/plugin_subscriptions")]
Task<IEnumerable<PluginSubscriptionContent>> GetPluginSubscription([Query("instance_id")] Guid instanceId,
[Query("subscription_id")] string subscription_id);
}

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
<PackageId>RaidMax.IW4MAdmin.Application</PackageId>
<Version>2020.0.0.0</Version>
@ -21,20 +21,21 @@
<Win32Resource />
<RootNamespace>IW4MAdmin.Application</RootNamespace>
<PublishWithAspNetCoreTargetManifest>false</PublishWithAspNetCoreTargetManifest>
<Nullable>disable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Jint" Version="3.0.0-beta-2049" />
<PackageReference Include="MaxMind.GeoIP2" Version="5.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.8">
<PackageReference Include="Jint" Version="3.0.0" />
<PackageReference Include="MaxMind.GeoIP2" Version="5.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="RestEase" Version="1.5.7" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Refit" Version="7.0.0" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageReference Include="System.CommandLine.DragonFruit" Version="0.4.0-alpha.22272.1" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
</ItemGroup>
<PropertyGroup>

View File

@ -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)

View File

@ -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<GameLogReaderHttp> logger)
{
_eventParser = parser;
_logServerApi = RestClient.For<IGameLogServer>(gameLogServerUris[0].ToString());
_logServerApi = RestService.For<IGameLogServer>(gameLogServerUris[0].ToString());
_safeLogPath = gameLogServerUris[1].LocalPath.ToBase64UrlSafeString();
_logger = logger;
}

View File

@ -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<string, string>();
foreach (string filePath in localizationFiles)
foreach (var filePath in localizationFiles)
{
var localizationContents = File.ReadAllText(filePath, Encoding.UTF8);
var eachLocalizationFile = Newtonsoft.Json.JsonConvert.DeserializeObject<SharedLibraryCore.Localization.Layout>(localizationContents);
if (eachLocalizationFile == null)
var eachLocalizationFile = JsonSerializer.Deserialize<SharedLibraryCore.Localization.Layout>(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);
}
}
}

View File

@ -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<IMasterApi>(httpClient);
var masterRestClient = RestService.For<IMasterApi>(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

View File

@ -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<MasterCommunication> 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<ResultMessage> response;
IApiResponse<ResultMessage> 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);
}
}
}

View File

@ -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<IPAddress>
{
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<IPAddress>(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<ClientState>(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<EventType>(jsonObject["Type"].ToString()),
Subtype = jsonObject["Subtype"]?.ToString(),
Source = Enum.Parse<EventSource>(jsonObject["Source"].ToString()),
RequiredEntity = Enum.Parse<EventRequiredEntity>(jsonObject["RequiredEntity"].ToString()),
Data = jsonObject["Data"].ToString(),
Message = jsonObject["Message"].ToString(),
GameTime = (int?)jsonObject["GameTime"],
Origin = jsonObject["Origin"]?.ToObject<EFClient>(serializer),
Target = jsonObject["Target"]?.ToObject<EFClient>(serializer),
ImpersonationOrigin = jsonObject["ImpersonationOrigin"]?.ToObject<EFClient>(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<IPEndPoint>
{
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<EFClient>
{
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<GameEvent>
{
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<EFClient>(ref reader, options);
break;
case "Target":
gameEvent.Target = JsonSerializer.Deserialize<EFClient>(ref reader, options);
break;
case "ImpersonationOrigin":
gameEvent.ImpersonationOrigin = JsonSerializer.Deserialize<EFClient>(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();
}
}

View File

@ -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
{

View File

@ -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;

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Configurations>Debug;Release;Prerelease</Configurations>
<Platforms>AnyCPU</Platforms>
<Title>RaidMax.IW4MAdmin.Data</Title>
@ -9,16 +9,20 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.1">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql" Version="6.0.2" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.2" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.1" />
<PackageReference Include="Npgsql" Version="8.0.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.0-beta.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.1" />
</ItemGroup>
</Project>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<AssemblyName>Integrations.Cod</AssemblyName>
<RootNamespace>Integrations.Cod</RootNamespace>
<Configurations>Debug;Release;Prerelease</Configurations>
@ -17,7 +17,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="protobuf-net" Version="3.2.26" />
<PackageReference Include="protobuf-net" Version="3.2.30" />
</ItemGroup>
</Project>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<AssemblyName>Integrations.Source</AssemblyName>
<RootNamespace>Integrations.Source</RootNamespace>
<Configurations>Debug;Release;Prerelease</Configurations>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<LangVersion>Latest</LangVersion>
<Configurations>Debug;Release;Prerelease</Configurations>
@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.SyndicationFeed.ReaderWriter" Version="1.0.2" />
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2024.2.5.3" PrivateAssets="All" />
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2024.2.5.9" PrivateAssets="All" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RazorCompileOnBuild Condition="'$(CONFIG)'!='Debug'">true</RazorCompileOnBuild>
<RazorCompiledOnPublish Condition="'$(CONFIG)'!='Debug'">true</RazorCompiledOnPublish>
<PreserveCompilationContext Condition="'$(CONFIG)'!='Debug'">false</PreserveCompilationContext>
@ -16,7 +16,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2024.2.5.3" PrivateAssets="All" />
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2024.2.5.9" PrivateAssets="All" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ApplicationIcon />
<StartupObject />
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
@ -19,7 +19,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2024.2.5.3" PrivateAssets="All" />
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2024.2.5.9" PrivateAssets="All" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -1,18 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Authors>MrAmos123</Authors>
<OutputType>Library</OutputType>
<Configurations>Debug;Release;Prerelease</Configurations>
<Platforms>AnyCPU</Platforms>
<RootNamespace>IW4MAdmin.Plugins.Mute</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2024.2.5.3" PrivateAssets="All" />
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2024.2.5.9" PrivateAssets="All" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -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<Server.Game>();
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;

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ApplicationIcon />
<StartupObject />
<PackageId>RaidMax.IW4MAdmin.Plugins.ProfanityDeterment</PackageId>
@ -16,7 +16,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2024.2.5.3" PrivateAssets="All" />
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2024.2.5.9" PrivateAssets="All" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ApplicationIcon />
<StartupObject />
<PackageId>RaidMax.IW4MAdmin.Plugins.Stats</PackageId>
@ -17,7 +17,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2024.2.5.3" PrivateAssets="All" />
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2024.2.5.9" PrivateAssets="All" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -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"]

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ApplicationIcon />
<StartupObject />
<PackageId>RaidMax.IW4MAdmin.Plugins.Welcome</PackageId>
@ -20,7 +20,7 @@
</Target>
<ItemGroup>
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2024.2.5.3" PrivateAssets="All" />
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2024.2.5.9" PrivateAssets="All" />
</ItemGroup>
</Project>

View File

@ -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;

View File

@ -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;
/// <summary>
/// Config driven command properties
/// </summary>
public class CommandProperties
{
/// <summary>
/// Config driven command properties
/// Specifies the command name
/// </summary>
public class CommandProperties
{
/// <summary>
/// Specifies the command name
/// </summary>
public string Name { get; set; }
public string Name { get; set; }
/// <summary>
/// Alias of this command
/// </summary>
public string Alias { get; set; }
/// <summary>
/// Alias of this command
/// </summary>
public string Alias { get; set; }
/// <summary>
/// Specifies the minimum permission level needed to execute the
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public Permission MinimumPermission { get; set; }
/// <summary>
/// Specifies the minimum permission level needed to execute the
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public Permission MinimumPermission { get; set; }
/// <summary>
/// Indicates if the command can be run by another user (impersonation)
/// </summary>
public bool AllowImpersonation { get; set; }
/// <summary>
/// Indicates if the command can be run by another user (impersonation)
/// </summary>
public bool AllowImpersonation { get; set; }
/// <summary>
/// Specifies the games supporting the functionality of the command
/// </summary>
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
public Game[] SupportedGames { get; set; } = Array.Empty<Game>();
}
/// <summary>
/// Specifies the games supporting the functionality of the command
/// </summary>
[JsonConverter(typeof(GameArrayJsonConverter))]
public Game[] SupportedGames { get; set; } = Array.Empty<Game>();
}

View File

@ -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; }
}

View File

@ -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;
/// <summary>
/// JSON converter for the build number
/// </summary>
public class BuildNumberJsonConverter : JsonConverter<BuildNumber>
{
/// <summary>
/// JSON converter for the build number
/// </summary>
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);
}
var stringValue = reader.GetString();
return BuildNumber.Parse(stringValue);
}
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());
}
public override void Write(Utf8JsonWriter writer, BuildNumber value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
}
public class GameArrayJsonConverter : JsonConverter<Server.Game[]>
{
public override Server.Game[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
List<Server.Game> games = [];
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndArray)
{
break;
}
var gameString = reader.GetString();
var game = Enum.Parse<Server.Game>(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();
}
}

View File

@ -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
/// <returns></returns>
Task Kick(string reason, EFClient target, EFClient origin, EFPenalty previousPenalty = null);
IPEndPoint ResolvedIpEndPoint { get; }
IRConParser RconParser { get; }
/// <summary>
/// Execute a server command
/// </summary>

View File

@ -41,6 +41,7 @@ namespace SharedLibraryCore.Interfaces
ILogger GetLogger(long serverId);
IList<Server> GetServers();
List<Server> Servers { get; }
IList<IManagerCommand> GetCommands();
IList<MessageToken> GetMessageTokens();
IList<EFClient> GetActiveClients();

View File

@ -15,35 +15,35 @@ namespace SharedLibraryCore.Interfaces
/// <summary>
/// stores the game/client specific version (usually the value of the "version" DVAR)
/// </summary>
string Version { get; }
string Version { get; set; }
/// <summary>
/// specifies the game name (usually the internal studio iteration ie: IW4, T5 etc...)
/// </summary>
Game GameName { get; }
Game GameName { get; set; }
/// <summary>
/// indicates if the game supports generating a log path from DVAR retrieval
/// of fs_game, fs_basepath, g_log
/// </summary>
bool CanGenerateLogPath { get; }
bool CanGenerateLogPath { get; set; }
/// <summary>
/// specifies the name of the parser
/// </summary>
string Name { get; }
string Name { get; set; }
/// <summary>
/// specifies the type of rcon engine
/// eg: COD, Source
/// </summary>
string RConEngine { get; }
string RConEngine { get; set; }
/// <summary>
/// indicates that the game does not log to the mods folder (when mod is loaded),
/// but rather always to the fs_basegame directory
/// </summary>
bool IsOneLog { get; }
bool IsOneLog { get; set; }
/// <summary>
/// retrieves the value of a given DVAR
@ -54,7 +54,8 @@ namespace SharedLibraryCore.Interfaces
/// <param name="fallbackValue">default value to return if dvar retrieval fails</param>
/// <param name="token"></param>
/// <returns></returns>
Task<Dvar<T>> GetDvarAsync<T>(IRConConnection connection, string dvarName, T fallbackValue = default, CancellationToken token = default);
Task<Dvar<T>> GetDvarAsync<T>(IRConConnection connection, string dvarName, T fallbackValue = default,
CancellationToken token = default);
/// <summary>
/// set value of DVAR by name

View File

@ -10,74 +10,74 @@ namespace SharedLibraryCore.Interfaces
/// <summary>
/// stores the command format for console commands
/// </summary>
CommandPrefix CommandPrefixes { get; }
CommandPrefix CommandPrefixes { get; set; }
/// <summary>
/// stores the regex info for parsing get status response
/// </summary>
ParserRegex Status { get; }
ParserRegex Status { get; set; }
/// <summary>
/// stores regex info for parsing the map line from rcon status response
/// </summary>
ParserRegex MapStatus { get; }
ParserRegex MapStatus { get; set; }
/// <summary>
/// stores regex info for parsing the gametype line from rcon status response
/// </summary>
ParserRegex GametypeStatus { get; }
ParserRegex GametypeStatus { get; set; }
/// <summary>
/// stores regex info for parsing hostname line from rcon status response
/// </summary>
ParserRegex HostnameStatus { get; }
ParserRegex HostnameStatus { get; set; }
/// <summary>
/// stores regex info for parsing max players line from rcon status response
/// </summary>
ParserRegex MaxPlayersStatus { get; }
ParserRegex MaxPlayersStatus { get; set; }
/// <summary>
/// stores the regex info for parsing get DVAR responses
/// </summary>
ParserRegex Dvar { get; }
ParserRegex Dvar { get; set; }
/// <summary>
/// stores the regex info for parsing the header of a status response
/// </summary>
ParserRegex StatusHeader { get; }
ParserRegex StatusHeader { get; set; }
/// <summary>
/// Specifies the expected response message from rcon when the server is not running
/// </summary>
string ServerNotRunningResponse { get; }
string ServerNotRunningResponse { get; set; }
/// <summary>
/// indicates if the application should wait for response from server
/// when executing a command
/// </summary>
bool WaitForResponse { get; }
bool WaitForResponse { get; set; }
/// <summary>
/// indicates the format expected for parsed guids
/// </summary>
NumberStyles GuidNumberStyle { get; }
NumberStyles GuidNumberStyle { get; set; }
/// <summary>
/// specifies simple mappings for dvar names in scenarios where the needed
/// information is not stored in a traditional dvar name
/// </summary>
IDictionary<string, string> OverrideDvarNameMapping { get; }
IDictionary<string, string> OverrideDvarNameMapping { get; set; }
/// <summary>
/// specifies the default dvar values for games that don't support certain dvars
/// </summary>
IDictionary<string, string> DefaultDvarValues { get; }
IDictionary<string, string> DefaultDvarValues { get; set; }
/// <summary>
/// contains a setup of commands that have override timeouts
/// </summary>
IDictionary<string, int?> OverrideCommandTimeouts { get; }
IDictionary<string, int?> OverrideCommandTimeouts { get; set; }
/// <summary>
/// specifies how many lines can be used for ingame notice
@ -87,29 +87,30 @@ namespace SharedLibraryCore.Interfaces
/// <summary>
/// specifies how many characters can be displayed per notice line
/// </summary>
int NoticeMaxCharactersPerLine { get; }
int NoticeMaxCharactersPerLine { get; set; }
/// <summary>
/// specifies the characters used to split a line
/// </summary>
string NoticeLineSeparator { get; }
string NoticeLineSeparator { get; set; }
/// <summary>
/// Default port the game listens to RCon requests on
/// </summary>
int? DefaultRConPort { get; }
int? DefaultRConPort { get; set; }
/// <summary>
/// Default Indicator of where the game is installed (ex file path or registry entry)
/// </summary>
string DefaultInstallationDirectoryHint { get; }
string DefaultInstallationDirectoryHint { get; set; }
ColorCodeMapping ColorCodeMapping { get; }
ColorCodeMapping ColorCodeMapping { get; set; }
short FloodProtectInterval { get; set; }
short FloodProtectInterval { get; }
/// <summary>
/// indicates if diacritics (accented characters) should be normalized
/// </summary>
bool ShouldRemoveDiacritics { get; }
bool ShouldRemoveDiacritics { get; set; }
}
}

View File

@ -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<string, string> 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

View File

@ -2,9 +2,9 @@
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId>
<Version>2023.4.5.1</Version>
<Version>2024.01.01.1</Version>
<Authors>RaidMax</Authors>
<Company>Forever None</Company>
<Configurations>Debug;Release;Prerelease</Configurations>
@ -19,7 +19,7 @@
<IsPackable>true</IsPackable>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Description>Shared Library for IW4MAdmin</Description>
<PackageVersion>2023.4.5.1</PackageVersion>
<PackageVersion>2024.01.01.1</PackageVersion>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
@ -34,31 +34,30 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation" Version="11.2.1" />
<PackageReference Include="FluentValidation" Version="11.9.0" />
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Humanizer.Core.ru" Version="2.14.1" />
<PackageReference Include="Humanizer.Core.de" Version="2.14.1" />
<PackageReference Include="Humanizer.Core.es" Version="2.14.1" />
<PackageReference Include="Humanizer.Core.pt" Version="2.14.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.8" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="6.0.8" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="6.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Serilog.AspNetCore" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Data\Data.csproj">
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<IncludeAssets>Data.dll</IncludeAssets>
</ProjectReference>
<ProjectReference Include="..\Data\Data.csproj">
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<IncludeAssets>Data.dll</IncludeAssets>
</ProjectReference>
</ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">

View File

@ -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))

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RazorCompileOnBuild Condition="'$(CONFIG)'!='Debug'">true</RazorCompileOnBuild>
<RazorCompiledOnPublish Condition="'$(CONFIG)'!='Debug'">true</RazorCompiledOnPublish>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
@ -46,9 +46,9 @@
<ItemGroup>
<PackageReference Include="BuildWebCompiler2022" Version="1.14.10" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.2.2" />
<PackageReference Include="Microsoft.AspNetCore.ConcurrencyLimiter" Version="6.0.16" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.8" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
<PackageReference Include="Microsoft.AspNetCore.ConcurrencyLimiter" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.1" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />
</ItemGroup>