refactor a good bit of stuff for better dependency injection
fix regular expression for T6 log parsing
This commit is contained in:
parent
ec053eb854
commit
c3c21a7749
@ -58,11 +58,12 @@ namespace IW4MAdmin.Application
|
||||
private readonly Dictionary<string, Task<IList>> _operationLookup = new Dictionary<string, Task<IList>>();
|
||||
private readonly ITranslationLookup _translationLookup;
|
||||
private readonly IConfigurationHandler<CommandConfiguration> _commandConfiguration;
|
||||
private readonly IPluginImporter _pluginImporter;
|
||||
private readonly IGameServerInstanceFactory _serverInstanceFactory;
|
||||
|
||||
public ApplicationManager(ILogger logger, IMiddlewareActionHandler actionHandler, IEnumerable<IManagerCommand> commands,
|
||||
ITranslationLookup translationLookup, IConfigurationHandler<CommandConfiguration> commandConfiguration,
|
||||
IConfigurationHandler<ApplicationConfiguration> appConfigHandler, IPluginImporter pluginImporter)
|
||||
IConfigurationHandler<ApplicationConfiguration> appConfigHandler, IGameServerInstanceFactory serverInstanceFactory,
|
||||
IEnumerable<IPlugin> plugins)
|
||||
{
|
||||
MiddlewareActionHandler = actionHandler;
|
||||
_servers = new ConcurrentBag<Server>();
|
||||
@ -73,8 +74,8 @@ namespace IW4MAdmin.Application
|
||||
ConfigHandler = appConfigHandler;
|
||||
StartTime = DateTime.UtcNow;
|
||||
PageList = new PageList();
|
||||
AdditionalEventParsers = new List<IEventParser>();
|
||||
AdditionalRConParsers = new List<IRConParser>();
|
||||
AdditionalEventParsers = new List<IEventParser>() { new BaseEventParser() };
|
||||
AdditionalRConParsers = new List<IRConParser>() { new BaseRConParser() };
|
||||
TokenAuthenticator = new TokenAuthentication();
|
||||
_metaService = new MetaService();
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
@ -82,9 +83,12 @@ namespace IW4MAdmin.Application
|
||||
_commands = commands.ToList();
|
||||
_translationLookup = translationLookup;
|
||||
_commandConfiguration = commandConfiguration;
|
||||
_pluginImporter = pluginImporter;
|
||||
_serverInstanceFactory = serverInstanceFactory;
|
||||
Plugins = plugins;
|
||||
}
|
||||
|
||||
public IEnumerable<IPlugin> Plugins { get; }
|
||||
|
||||
public async Task ExecuteEvent(GameEvent newEvent)
|
||||
{
|
||||
#if DEBUG == true
|
||||
@ -249,7 +253,7 @@ namespace IW4MAdmin.Application
|
||||
ExternalIPAddress = await Utilities.GetExternalIP();
|
||||
|
||||
#region PLUGINS
|
||||
foreach (var plugin in _pluginImporter.ActivePlugins)
|
||||
foreach (var plugin in Plugins)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -567,7 +571,8 @@ namespace IW4MAdmin.Application
|
||||
|
||||
try
|
||||
{
|
||||
var ServerInstance = new IW4MServer(this, Conf, _translationLookup, _pluginImporter);
|
||||
// todo: this might not always be an IW4MServer
|
||||
var ServerInstance = _serverInstanceFactory.CreateServer(Conf, this) as IW4MServer;
|
||||
await ServerInstance.Initialize();
|
||||
|
||||
_servers.Add(ServerInstance);
|
||||
@ -759,11 +764,6 @@ namespace IW4MAdmin.Application
|
||||
return Handler;
|
||||
}
|
||||
|
||||
public IList<Assembly> GetPluginAssemblies()
|
||||
{
|
||||
return _pluginImporter.PluginAssemblies.Union(_pluginImporter.Assemblies).ToList();
|
||||
}
|
||||
|
||||
public IPageList GetPageList()
|
||||
{
|
||||
return PageList;
|
||||
|
@ -9,7 +9,7 @@ using static SharedLibraryCore.Server;
|
||||
|
||||
namespace IW4MAdmin.Application.EventParsers
|
||||
{
|
||||
class BaseEventParser : IEventParser
|
||||
public class BaseEventParser : IEventParser
|
||||
{
|
||||
public BaseEventParser()
|
||||
{
|
||||
@ -37,7 +37,7 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3);
|
||||
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginName, 4);
|
||||
|
||||
Configuration.Damage.Pattern = @"^(D);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+);(-?[0-9]+);(axis|allies|world)?;(.{1,24});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+)?;-?([0-9]+);(axis|allies|world)?;(.{1,24})?;((?:[0-9]+|[a-z]+|_)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$";
|
||||
Configuration.Damage.Pattern = @"^(D);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+);(-?[0-9]+);(axis|allies|world)?;([^;]{1,24});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+)?;-?([0-9]+);(axis|allies|world)?;([^;]{1,24})?;((?:[0-9]+|[a-z]+|_|\+)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$";
|
||||
Configuration.Damage.AddMapping(ParserRegex.GroupType.EventType, 1);
|
||||
Configuration.Damage.AddMapping(ParserRegex.GroupType.TargetNetworkId, 2);
|
||||
Configuration.Damage.AddMapping(ParserRegex.GroupType.TargetClientNumber, 3);
|
||||
@ -52,7 +52,7 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
Configuration.Damage.AddMapping(ParserRegex.GroupType.MeansOfDeath, 12);
|
||||
Configuration.Damage.AddMapping(ParserRegex.GroupType.HitLocation, 13);
|
||||
|
||||
Configuration.Kill.Pattern = @"^(K);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+);(-?[0-9]+);(axis|allies|world)?;(.{1,24});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+)?;-?([0-9]+);(axis|allies|world)?;(.{1,24})?;((?:[0-9]+|[a-z]+|_)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$";
|
||||
Configuration.Kill.Pattern = @"^(K);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+);(-?[0-9]+);(axis|allies|world)?;([^;]{1,24});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+)?;-?([0-9]+);(axis|allies|world)?;([^;]{1,24})?;((?:[0-9]+|[a-z]+|_|\+)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$";
|
||||
Configuration.Kill.AddMapping(ParserRegex.GroupType.EventType, 1);
|
||||
Configuration.Kill.AddMapping(ParserRegex.GroupType.TargetNetworkId, 2);
|
||||
Configuration.Kill.AddMapping(ParserRegex.GroupType.TargetClientNumber, 3);
|
||||
|
23
Application/Factories/ConfigurationHandlerFactory.cs
Normal file
23
Application/Factories/ConfigurationHandlerFactory.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using IW4MAdmin.Application.Misc;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
|
||||
namespace IW4MAdmin.Application.Factories
|
||||
{
|
||||
/// <summary>
|
||||
/// implementation of IConfigurationHandlerFactory
|
||||
/// provides base functionality to create configuration handlers
|
||||
/// </summary>
|
||||
public class ConfigurationHandlerFactory : IConfigurationHandlerFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// creates a base configuration handler
|
||||
/// </summary>
|
||||
/// <typeparam name="T">base configuration type</typeparam>
|
||||
/// <param name="name">name of the config file</param>
|
||||
/// <returns></returns>
|
||||
public IConfigurationHandler<T> GetConfigurationHandler<T>(string name) where T : IBaseConfiguration
|
||||
{
|
||||
return new BaseConfigurationHandler<T>(name);
|
||||
}
|
||||
}
|
||||
}
|
38
Application/Factories/GameServerInstanceFactory.cs
Normal file
38
Application/Factories/GameServerInstanceFactory.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Configuration;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System.Collections;
|
||||
|
||||
namespace IW4MAdmin.Application.Factories
|
||||
{
|
||||
/// <summary>
|
||||
/// implementation of IGameServerInstanceFactory
|
||||
/// </summary>
|
||||
internal class GameServerInstanceFactory : IGameServerInstanceFactory
|
||||
{
|
||||
private readonly ITranslationLookup _translationLookup;
|
||||
private readonly IRConConnectionFactory _rconConnectionFactory;
|
||||
|
||||
/// <summary>
|
||||
/// base constructor
|
||||
/// </summary>
|
||||
/// <param name="translationLookup"></param>
|
||||
/// <param name="rconConnectionFactory"></param>
|
||||
public GameServerInstanceFactory(ITranslationLookup translationLookup, IRConConnectionFactory rconConnectionFactory)
|
||||
{
|
||||
_translationLookup = translationLookup;
|
||||
_rconConnectionFactory = rconConnectionFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// creates an IW4MServer instance
|
||||
/// </summary>
|
||||
/// <param name="config">server configuration</param>
|
||||
/// <param name="manager">application manager</param>
|
||||
/// <returns></returns>
|
||||
public Server CreateServer(ServerConfiguration config, IManager manager)
|
||||
{
|
||||
return new IW4MServer(manager, config, _translationLookup, _rconConnectionFactory);
|
||||
}
|
||||
}
|
||||
}
|
36
Application/Factories/RConConnectionFactory.cs
Normal file
36
Application/Factories/RConConnectionFactory.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using IW4MAdmin.Application.RCon;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System.Text;
|
||||
|
||||
namespace IW4MAdmin.Application.Factories
|
||||
{
|
||||
/// <summary>
|
||||
/// implementation of IRConConnectionFactory
|
||||
/// </summary>
|
||||
internal class RConConnectionFactory : IRConConnectionFactory
|
||||
{
|
||||
private static readonly Encoding gameEncoding = Encoding.GetEncoding("windows-1252");
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Base constructor
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
public RConConnectionFactory(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// creates a new rcon connection instance
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">ip address of the server</param>
|
||||
/// <param name="port">port of the server</param>
|
||||
/// <param name="password">rcon password of the server</param>
|
||||
/// <returns></returns>
|
||||
public IRConConnection CreateConnection(string ipAddress, int port, string password)
|
||||
{
|
||||
return new RConConnection(ipAddress, port, password, _logger, gameEncoding);
|
||||
}
|
||||
}
|
||||
}
|
@ -27,15 +27,14 @@ namespace IW4MAdmin
|
||||
private GameLogEventDetection LogEvent;
|
||||
private readonly ITranslationLookup _translationLookup;
|
||||
private const int REPORT_FLAG_COUNT = 4;
|
||||
private readonly IPluginImporter _pluginImporter;
|
||||
private int lastGameTime = 0;
|
||||
|
||||
public int Id { get; private set; }
|
||||
|
||||
public IW4MServer(IManager mgr, ServerConfiguration cfg, ITranslationLookup lookup, IPluginImporter pluginImporter) : base(mgr, cfg)
|
||||
public IW4MServer(IManager mgr, ServerConfiguration cfg, ITranslationLookup lookup,
|
||||
IRConConnectionFactory connectionFactory) : base(mgr, connectionFactory, cfg)
|
||||
{
|
||||
_translationLookup = lookup;
|
||||
_pluginImporter = pluginImporter;
|
||||
}
|
||||
|
||||
override public async Task<EFClient> OnClientConnected(EFClient clientFromLog)
|
||||
@ -66,6 +65,7 @@ namespace IW4MAdmin
|
||||
client.Score = clientFromLog.Score;
|
||||
client.Ping = clientFromLog.Ping;
|
||||
client.CurrentServer = this;
|
||||
client.State = ClientState.Connecting;
|
||||
|
||||
Clients[client.ClientNumber] = client;
|
||||
#if DEBUG == true
|
||||
@ -153,7 +153,7 @@ namespace IW4MAdmin
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var plugin in _pluginImporter.ActivePlugins)
|
||||
foreach (var plugin in Manager.Plugins)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -182,6 +182,11 @@ namespace IW4MAdmin
|
||||
catch (Exception e)
|
||||
{
|
||||
lastException = e;
|
||||
|
||||
if (E.Origin != null)
|
||||
{
|
||||
E.Origin.Tell(_translationLookup["SERVER_ERROR_COMMAND_INGAME"]);
|
||||
}
|
||||
}
|
||||
|
||||
finally
|
||||
@ -695,7 +700,7 @@ namespace IW4MAdmin
|
||||
await e.WaitAsync(Utilities.DefaultCommandTimeout, new CancellationTokenRegistration().Token);
|
||||
}
|
||||
|
||||
foreach (var plugin in _pluginImporter.ActivePlugins)
|
||||
foreach (var plugin in Manager.Plugins)
|
||||
{
|
||||
await plugin.OnUnloadAsync();
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
using IW4MAdmin.Application.Helpers;
|
||||
using IW4MAdmin.Application.Factories;
|
||||
using IW4MAdmin.Application.Helpers;
|
||||
using IW4MAdmin.Application.IO;
|
||||
using IW4MAdmin.Application.Migration;
|
||||
using IW4MAdmin.Application.Misc;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@ -8,7 +10,6 @@ using SharedLibraryCore.Exceptions;
|
||||
using SharedLibraryCore.Helpers;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
@ -266,27 +267,21 @@ namespace IW4MAdmin.Application
|
||||
/// </summary>
|
||||
private static IServiceCollection ConfigureServices()
|
||||
{
|
||||
var defaultLogger = new Logger("IW4MAdmin-Manager");
|
||||
var pluginImporter = new PluginImporter(defaultLogger);
|
||||
|
||||
var serviceCollection = new ServiceCollection();
|
||||
serviceCollection.AddSingleton<IServiceCollection>(_serviceProvider => serviceCollection)
|
||||
.AddSingleton(new BaseConfigurationHandler<ApplicationConfiguration>("IW4MAdminSettings") as IConfigurationHandler<ApplicationConfiguration>)
|
||||
.AddSingleton(new BaseConfigurationHandler<CommandConfiguration>("CommandConfiguration") as IConfigurationHandler<CommandConfiguration>)
|
||||
.AddSingleton(_serviceProvider => _serviceProvider.GetRequiredService<IConfigurationHandler<ApplicationConfiguration>>().Configuration())
|
||||
.AddSingleton(_serviceProvider => _serviceProvider.GetRequiredService<IConfigurationHandler<CommandConfiguration>>().Configuration() ?? new CommandConfiguration())
|
||||
.AddSingleton<ILogger>(_serviceProvider => new Logger("IW4MAdmin-Manager"))
|
||||
.AddSingleton<ILogger>(_serviceProvider => defaultLogger)
|
||||
.AddSingleton<IPluginImporter, PluginImporter>()
|
||||
.AddSingleton<IMiddlewareActionHandler, MiddlewareActionHandler>()
|
||||
.AddTransient(_serviceProvider =>
|
||||
{
|
||||
var importer = _serviceProvider.GetRequiredService<IPluginImporter>();
|
||||
var config = _serviceProvider.GetRequiredService<CommandConfiguration>();
|
||||
var layout = _serviceProvider.GetRequiredService<ITranslationLookup>();
|
||||
|
||||
// todo: this is disgusting, but I need it until I can figure out a way to dynamically load the plugins without creating an instance.
|
||||
return importer.CommandTypes.
|
||||
Union(typeof(SharedLibraryCore.Commands.QuitCommand).Assembly.GetTypes()
|
||||
.Where(_command => _command.BaseType == typeof(Command)))
|
||||
.Select(_cmdType => Activator.CreateInstance(_cmdType, config, layout) as IManagerCommand);
|
||||
})
|
||||
.AddSingleton<IRConConnectionFactory, RConConnectionFactory>()
|
||||
.AddSingleton<IGameServerInstanceFactory, GameServerInstanceFactory>()
|
||||
.AddSingleton<IConfigurationHandlerFactory, ConfigurationHandlerFactory>()
|
||||
.AddSingleton(_serviceProvider =>
|
||||
{
|
||||
var config = _serviceProvider.GetRequiredService<IConfigurationHandler<ApplicationConfiguration>>().Configuration();
|
||||
@ -295,6 +290,35 @@ namespace IW4MAdmin.Application
|
||||
})
|
||||
.AddSingleton<IManager, ApplicationManager>();
|
||||
|
||||
// register the native commands
|
||||
foreach (var commandType in typeof(SharedLibraryCore.Commands.QuitCommand).Assembly.GetTypes()
|
||||
.Where(_command => _command.BaseType == typeof(Command)))
|
||||
{
|
||||
defaultLogger.WriteInfo($"Registered native command type {commandType.Name}");
|
||||
serviceCollection.AddSingleton(typeof(IManagerCommand), commandType);
|
||||
}
|
||||
|
||||
// register the plugin implementations
|
||||
var pluginImplementations = pluginImporter.DiscoverAssemblyPluginImplementations();
|
||||
foreach (var pluginType in pluginImplementations.Item1)
|
||||
{
|
||||
defaultLogger.WriteInfo($"Registered plugin type {pluginType.FullName}");
|
||||
serviceCollection.AddSingleton(typeof(IPlugin), pluginType);
|
||||
}
|
||||
|
||||
// register the plugin commands
|
||||
foreach (var commandType in pluginImplementations.Item2)
|
||||
{
|
||||
defaultLogger.WriteInfo($"Registered plugin command type {commandType.FullName}");
|
||||
serviceCollection.AddSingleton(typeof(IManagerCommand), commandType);
|
||||
}
|
||||
|
||||
// register any script plugins
|
||||
foreach (var scriptPlugin in pluginImporter.DiscoverScriptPlugins())
|
||||
{
|
||||
serviceCollection.AddSingleton(scriptPlugin);
|
||||
}
|
||||
|
||||
return serviceCollection;
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,11 @@ namespace IW4MAdmin.Application.Migration
|
||||
{
|
||||
Directory.CreateDirectory(Path.Join(Utilities.OperatingDirectory, "Log"));
|
||||
}
|
||||
|
||||
if (!Directory.Exists(Path.Join(Utilities.OperatingDirectory, "Localization")))
|
||||
{
|
||||
Directory.CreateDirectory(Path.Join(Utilities.OperatingDirectory, "Localization"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,12 +1,17 @@
|
||||
using Newtonsoft.Json;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Exceptions;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibraryCore.Configuration
|
||||
namespace IW4MAdmin.Application.Misc
|
||||
{
|
||||
/// <summary>
|
||||
/// default implementation of IConfigurationHandler
|
||||
/// </summary>
|
||||
/// <typeparam name="T">base configuration type</typeparam>
|
||||
public class BaseConfigurationHandler<T> : IConfigurationHandler<T> where T : IBaseConfiguration
|
||||
{
|
||||
T _configuration;
|
@ -1,12 +1,14 @@
|
||||
using SharedLibraryCore;
|
||||
using IW4MAdmin.Application.IO;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace IW4MAdmin.Application
|
||||
{
|
||||
class Logger : ILogger
|
||||
public class Logger : ILogger
|
||||
{
|
||||
enum LogType
|
||||
{
|
||||
@ -77,9 +79,7 @@ namespace IW4MAdmin.Application
|
||||
{
|
||||
#if DEBUG
|
||||
// lets keep it simple and dispose of everything quickly as logging wont be that much (relatively)
|
||||
Console.WriteLine(LogLine);
|
||||
//File.AppendAllText(FileName, $"{LogLine}{Environment.NewLine}");
|
||||
//Debug.WriteLine(msg);
|
||||
Console.WriteLine(msg);
|
||||
#else
|
||||
if (type == LogType.Error || type == LogType.Verbose)
|
||||
{
|
||||
|
@ -5,111 +5,84 @@ using System.Reflection;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System.Linq;
|
||||
using SharedLibraryCore;
|
||||
using IW4MAdmin.Application.Misc;
|
||||
|
||||
namespace IW4MAdmin.Application.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// implementation of IPluginImporter
|
||||
/// discovers plugins and script plugins
|
||||
/// </summary>
|
||||
public class PluginImporter : IPluginImporter
|
||||
{
|
||||
public IList<Type> CommandTypes { get; private set; } = new List<Type>();
|
||||
public IList<IPlugin> ActivePlugins { get; private set; } = new List<IPlugin>();
|
||||
public IList<Assembly> PluginAssemblies { get; private set; } = new List<Assembly>();
|
||||
public IList<Assembly> Assemblies { get; private set; } = new List<Assembly>();
|
||||
|
||||
private static readonly string PLUGIN_DIR = "Plugins";
|
||||
private readonly ILogger _logger;
|
||||
private readonly ITranslationLookup _translationLookup;
|
||||
|
||||
public PluginImporter(ILogger logger, ITranslationLookup translationLookup)
|
||||
public PluginImporter(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_translationLookup = translationLookup;
|
||||
|
||||
Load();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads all the assembly and javascript plugins
|
||||
/// discovers all the script plugins in the plugins dir
|
||||
/// </summary>
|
||||
private void Load()
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IPlugin> DiscoverScriptPlugins()
|
||||
{
|
||||
string pluginDir = $"{Utilities.OperatingDirectory}Plugins{Path.DirectorySeparatorChar}";
|
||||
string[] dllFileNames = null;
|
||||
string[] scriptFileNames = null;
|
||||
string pluginDir = $"{Utilities.OperatingDirectory}{PLUGIN_DIR}{Path.DirectorySeparatorChar}";
|
||||
|
||||
if (Directory.Exists(pluginDir))
|
||||
{
|
||||
dllFileNames = Directory.GetFiles($"{Utilities.OperatingDirectory}Plugins{Path.DirectorySeparatorChar}", "*.dll");
|
||||
scriptFileNames = Directory.GetFiles($"{Utilities.OperatingDirectory}Plugins{Path.DirectorySeparatorChar}", "*.js");
|
||||
}
|
||||
string[] scriptPluginFiles = Directory.GetFiles(pluginDir, "*.js");
|
||||
|
||||
else
|
||||
{
|
||||
dllFileNames = new string[0];
|
||||
scriptFileNames = new string[0];
|
||||
}
|
||||
_logger.WriteInfo($"Discovered {scriptPluginFiles.Length} potential script plugins");
|
||||
|
||||
if (dllFileNames.Length == 0 &&
|
||||
scriptFileNames.Length == 0)
|
||||
{
|
||||
_logger.WriteDebug(_translationLookup["PLUGIN_IMPORTER_NOTFOUND"]);
|
||||
return;
|
||||
}
|
||||
|
||||
// load up the script plugins
|
||||
foreach (string fileName in scriptFileNames)
|
||||
{
|
||||
var plugin = new ScriptPlugin(fileName);
|
||||
_logger.WriteDebug($"Loaded script plugin \"{ plugin.Name }\" [{plugin.Version}]");
|
||||
ActivePlugins.Add(plugin);
|
||||
}
|
||||
|
||||
ICollection<Assembly> assemblies = new List<Assembly>(dllFileNames.Length);
|
||||
foreach (string dllFile in dllFileNames)
|
||||
{
|
||||
assemblies.Add(Assembly.LoadFrom(dllFile));
|
||||
}
|
||||
|
||||
int LoadedCommands = 0;
|
||||
foreach (Assembly Plugin in assemblies)
|
||||
{
|
||||
if (Plugin != null)
|
||||
if (scriptPluginFiles.Length > 0)
|
||||
{
|
||||
Assemblies.Add(Plugin);
|
||||
Type[] types = Plugin.GetTypes();
|
||||
foreach (Type assemblyType in types)
|
||||
foreach (string fileName in scriptPluginFiles)
|
||||
{
|
||||
if (assemblyType.IsClass && assemblyType.BaseType == typeof(Command))
|
||||
{
|
||||
CommandTypes.Add(assemblyType);
|
||||
_logger.WriteDebug($"{_translationLookup["PLUGIN_IMPORTER_REGISTERCMD"]} \"{assemblyType.Name}\"");
|
||||
LoadedCommands++;
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (assemblyType.GetInterface("IPlugin", false) == null)
|
||||
continue;
|
||||
|
||||
var notifyObject = Activator.CreateInstance(assemblyType);
|
||||
IPlugin newNotify = (IPlugin)notifyObject;
|
||||
if (ActivePlugins.FirstOrDefault(x => x.Name == newNotify.Name) == null)
|
||||
{
|
||||
ActivePlugins.Add(newNotify);
|
||||
PluginAssemblies.Add(Plugin);
|
||||
_logger.WriteDebug($"Loaded plugin \"{newNotify.Name}\" [{newNotify.Version}]");
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.WriteWarning(_translationLookup["PLUGIN_IMPORTER_ERROR"].FormatExt(Plugin.Location));
|
||||
_logger.WriteDebug(e.GetExceptionInfo());
|
||||
}
|
||||
_logger.WriteInfo($"Discovered script plugin {fileName}");
|
||||
var plugin = new ScriptPlugin(fileName);
|
||||
yield return plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_logger.WriteInfo($"Loaded {ActivePlugins.Count} plugins and registered {LoadedCommands} plugin commands.");
|
||||
/// <summary>
|
||||
/// discovers all the C# assembly plugins and commands
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public (IEnumerable<Type>, IEnumerable<Type>) DiscoverAssemblyPluginImplementations()
|
||||
{
|
||||
string pluginDir = $"{Utilities.OperatingDirectory}{PLUGIN_DIR}{Path.DirectorySeparatorChar}";
|
||||
var pluginTypes = Enumerable.Empty<Type>();
|
||||
var commandTypes = Enumerable.Empty<Type>();
|
||||
|
||||
if (Directory.Exists(pluginDir))
|
||||
{
|
||||
var dllFileNames = Directory.GetFiles(pluginDir, "*.dll");
|
||||
_logger.WriteInfo($"Discovered {dllFileNames.Length} potential plugin assemblies");
|
||||
|
||||
if (dllFileNames.Length > 0)
|
||||
{
|
||||
var assemblies = dllFileNames.Select(_name => Assembly.LoadFrom(_name));
|
||||
|
||||
pluginTypes = assemblies
|
||||
.SelectMany(_asm => _asm.GetTypes())
|
||||
.Where(_assemblyType => _assemblyType.GetInterface(nameof(IPlugin), false) != null);
|
||||
|
||||
_logger.WriteInfo($"Discovered {pluginTypes.Count()} plugin implementations");
|
||||
|
||||
commandTypes = assemblies
|
||||
.SelectMany(_asm => _asm.GetTypes())
|
||||
.Where(_assemblyType => _assemblyType.IsClass && _assemblyType.BaseType == typeof(Command));
|
||||
|
||||
_logger.WriteInfo($"Discovered {commandTypes.Count()} plugin commands");
|
||||
}
|
||||
}
|
||||
|
||||
return (pluginTypes, commandTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,19 @@
|
||||
using Jint;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibraryCore
|
||||
namespace IW4MAdmin.Application.Misc
|
||||
{
|
||||
/// <summary>
|
||||
/// implementation of IPlugin
|
||||
/// used to proxy script plugin requests
|
||||
/// </summary>
|
||||
public class ScriptPlugin : IPlugin
|
||||
{
|
||||
public string Name { get; set; }
|
||||
@ -45,7 +49,6 @@ namespace SharedLibraryCore
|
||||
_onProcessing.Dispose();
|
||||
}
|
||||
|
||||
|
||||
public async Task Initialize(IManager manager)
|
||||
{
|
||||
await _onProcessing.WaitAsync();
|
29
Application/RCon/ConnectionState.cs
Normal file
29
Application/RCon/ConnectionState.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
|
||||
namespace IW4MAdmin.Application.RCon
|
||||
{
|
||||
/// <summary>
|
||||
/// used to keep track of the udp connection state
|
||||
/// </summary>
|
||||
internal class ConnectionState
|
||||
{
|
||||
~ConnectionState()
|
||||
{
|
||||
OnComplete.Dispose();
|
||||
OnSentData.Dispose();
|
||||
OnReceivedData.Dispose();
|
||||
}
|
||||
|
||||
public int ConnectionAttempts { get; set; }
|
||||
const int BufferSize = 4096;
|
||||
public readonly byte[] ReceiveBuffer = new byte[BufferSize];
|
||||
public readonly SemaphoreSlim OnComplete = new SemaphoreSlim(1, 1);
|
||||
public readonly ManualResetEventSlim OnSentData = new ManualResetEventSlim(false);
|
||||
public readonly ManualResetEventSlim OnReceivedData = new ManualResetEventSlim(false);
|
||||
public SocketAsyncEventArgs SendEventArgs { get; set; } = new SocketAsyncEventArgs();
|
||||
public SocketAsyncEventArgs ReceiveEventArgs { get; set; } = new SocketAsyncEventArgs();
|
||||
public DateTime LastQuery { get; set; } = DateTime.Now;
|
||||
}
|
||||
}
|
@ -1,58 +1,41 @@
|
||||
using SharedLibraryCore.Exceptions;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Exceptions;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using SharedLibraryCore.RCon;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibraryCore.RCon
|
||||
namespace IW4MAdmin.Application.RCon
|
||||
{
|
||||
class ConnectionState
|
||||
{
|
||||
~ConnectionState()
|
||||
{
|
||||
OnComplete.Dispose();
|
||||
OnSentData.Dispose();
|
||||
OnReceivedData.Dispose();
|
||||
}
|
||||
|
||||
public int ConnectionAttempts { get; set; }
|
||||
const int BufferSize = 4096;
|
||||
public readonly byte[] ReceiveBuffer = new byte[BufferSize];
|
||||
public readonly SemaphoreSlim OnComplete = new SemaphoreSlim(1, 1);
|
||||
public readonly ManualResetEventSlim OnSentData = new ManualResetEventSlim(false);
|
||||
public readonly ManualResetEventSlim OnReceivedData = new ManualResetEventSlim(false);
|
||||
public SocketAsyncEventArgs SendEventArgs { get; set; } = new SocketAsyncEventArgs();
|
||||
public SocketAsyncEventArgs ReceiveEventArgs { get; set; } = new SocketAsyncEventArgs();
|
||||
public DateTime LastQuery { get; set; } = DateTime.Now;
|
||||
}
|
||||
|
||||
public class Connection
|
||||
/// <summary>
|
||||
/// implementation of IRConConnection
|
||||
/// </summary>
|
||||
public class RConConnection : IRConConnection
|
||||
{
|
||||
static readonly ConcurrentDictionary<EndPoint, ConnectionState> ActiveQueries = new ConcurrentDictionary<EndPoint, ConnectionState>();
|
||||
public IPEndPoint Endpoint { get; private set; }
|
||||
public string RConPassword { get; private set; }
|
||||
|
||||
private readonly ILogger Log;
|
||||
private IRConParserConfiguration Config;
|
||||
private readonly Encoding defaultEncoding;
|
||||
private IRConParserConfiguration config;
|
||||
private readonly ILogger _log;
|
||||
private readonly Encoding _gameEncoding;
|
||||
|
||||
public Connection(string ipAddress, int port, string password, ILogger log, IRConParserConfiguration config)
|
||||
public RConConnection(string ipAddress, int port, string password, ILogger log, Encoding gameEncoding)
|
||||
{
|
||||
Endpoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
|
||||
defaultEncoding = Encoding.GetEncoding("windows-1252");
|
||||
_gameEncoding = gameEncoding;
|
||||
RConPassword = password;
|
||||
Log = log;
|
||||
Config = config;
|
||||
_log = log;
|
||||
}
|
||||
|
||||
public void SetConfiguration(IRConParserConfiguration config)
|
||||
{
|
||||
Config = config;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public async Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "")
|
||||
@ -65,7 +48,7 @@ namespace SharedLibraryCore.RCon
|
||||
var connectionState = ActiveQueries[this.Endpoint];
|
||||
|
||||
#if DEBUG == true
|
||||
Log.WriteDebug($"Waiting for semaphore to be released [{this.Endpoint}]");
|
||||
_log.WriteDebug($"Waiting for semaphore to be released [{this.Endpoint}]");
|
||||
#endif
|
||||
// enter the semaphore so only one query is sent at a time per server.
|
||||
await connectionState.OnComplete.WaitAsync();
|
||||
@ -80,17 +63,17 @@ namespace SharedLibraryCore.RCon
|
||||
connectionState.LastQuery = DateTime.Now;
|
||||
|
||||
#if DEBUG == true
|
||||
Log.WriteDebug($"Semaphore has been released [{this.Endpoint}]");
|
||||
Log.WriteDebug($"Query [{this.Endpoint},{type.ToString()},{parameters}]");
|
||||
_log.WriteDebug($"Semaphore has been released [{this.Endpoint}]");
|
||||
_log.WriteDebug($"Query [{this.Endpoint},{type.ToString()},{parameters}]");
|
||||
#endif
|
||||
|
||||
byte[] payload = null;
|
||||
bool waitForResponse = Config.WaitForResponse;
|
||||
bool waitForResponse = config.WaitForResponse;
|
||||
|
||||
string convertEncoding(string text)
|
||||
{
|
||||
byte[] convertedBytes = Utilities.EncodingType.GetBytes(text);
|
||||
return defaultEncoding.GetString(convertedBytes);
|
||||
return _gameEncoding.GetString(convertedBytes);
|
||||
}
|
||||
|
||||
try
|
||||
@ -102,25 +85,25 @@ namespace SharedLibraryCore.RCon
|
||||
{
|
||||
case StaticHelpers.QueryType.GET_DVAR:
|
||||
waitForResponse |= true;
|
||||
payload = string.Format(Config.CommandPrefixes.RConGetDvar, convertedRConPassword, convertedParameters + '\0').Select(Convert.ToByte).ToArray();
|
||||
payload = string.Format(config.CommandPrefixes.RConGetDvar, convertedRConPassword, convertedParameters + '\0').Select(Convert.ToByte).ToArray();
|
||||
break;
|
||||
case StaticHelpers.QueryType.SET_DVAR:
|
||||
payload = string.Format(Config.CommandPrefixes.RConSetDvar, convertedRConPassword, convertedParameters + '\0').Select(Convert.ToByte).ToArray();
|
||||
payload = string.Format(config.CommandPrefixes.RConSetDvar, convertedRConPassword, convertedParameters + '\0').Select(Convert.ToByte).ToArray();
|
||||
break;
|
||||
case StaticHelpers.QueryType.COMMAND:
|
||||
payload = string.Format(Config.CommandPrefixes.RConCommand, convertedRConPassword, convertedParameters + '\0').Select(Convert.ToByte).ToArray();
|
||||
payload = string.Format(config.CommandPrefixes.RConCommand, convertedRConPassword, convertedParameters + '\0').Select(Convert.ToByte).ToArray();
|
||||
break;
|
||||
case StaticHelpers.QueryType.GET_STATUS:
|
||||
waitForResponse |= true;
|
||||
payload = (Config.CommandPrefixes.RConGetStatus + '\0').Select(Convert.ToByte).ToArray();
|
||||
payload = (config.CommandPrefixes.RConGetStatus + '\0').Select(Convert.ToByte).ToArray();
|
||||
break;
|
||||
case StaticHelpers.QueryType.GET_INFO:
|
||||
waitForResponse |= true;
|
||||
payload = (Config.CommandPrefixes.RConGetInfo + '\0').Select(Convert.ToByte).ToArray();
|
||||
payload = (config.CommandPrefixes.RConGetInfo + '\0').Select(Convert.ToByte).ToArray();
|
||||
break;
|
||||
case StaticHelpers.QueryType.COMMAND_STATUS:
|
||||
waitForResponse |= true;
|
||||
payload = string.Format(Config.CommandPrefixes.RConCommand, convertedRConPassword, "status\0").Select(Convert.ToByte).ToArray();
|
||||
payload = string.Format(config.CommandPrefixes.RConCommand, convertedRConPassword, "status\0").Select(Convert.ToByte).ToArray();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -148,7 +131,7 @@ namespace SharedLibraryCore.RCon
|
||||
connectionState.OnReceivedData.Reset();
|
||||
connectionState.ConnectionAttempts++;
|
||||
#if DEBUG == true
|
||||
Log.WriteDebug($"Sending {payload.Length} bytes to [{this.Endpoint}] ({connectionState.ConnectionAttempts}/{StaticHelpers.AllowedConnectionFails})");
|
||||
_log.WriteDebug($"Sending {payload.Length} bytes to [{this.Endpoint}] ({connectionState.ConnectionAttempts}/{StaticHelpers.AllowedConnectionFails})");
|
||||
#endif
|
||||
try
|
||||
{
|
||||
@ -182,7 +165,7 @@ namespace SharedLibraryCore.RCon
|
||||
}
|
||||
}
|
||||
|
||||
string responseString = defaultEncoding.GetString(response, 0, response.Length) + '\n';
|
||||
string responseString = _gameEncoding.GetString(response, 0, response.Length) + '\n';
|
||||
|
||||
// note: not all games respond if the pasword is wrong or not set
|
||||
if (responseString.Contains("Invalid password") || responseString.Contains("rconpassword"))
|
||||
@ -195,7 +178,7 @@ namespace SharedLibraryCore.RCon
|
||||
throw new NetworkException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_RCON_NOTSET"]);
|
||||
}
|
||||
|
||||
if (responseString.Contains(Config.ServerNotRunningResponse))
|
||||
if (responseString.Contains(config.ServerNotRunningResponse))
|
||||
{
|
||||
throw new ServerException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_NOT_RUNNING"].FormatExt(Endpoint.ToString()));
|
||||
}
|
||||
@ -269,7 +252,7 @@ namespace SharedLibraryCore.RCon
|
||||
private void OnDataReceived(object sender, SocketAsyncEventArgs e)
|
||||
{
|
||||
#if DEBUG == true
|
||||
Log.WriteDebug($"Read {e.BytesTransferred} bytes from {e.RemoteEndPoint.ToString()}");
|
||||
_log.WriteDebug($"Read {e.BytesTransferred} bytes from {e.RemoteEndPoint.ToString()}");
|
||||
#endif
|
||||
ActiveQueries[this.Endpoint].OnReceivedData.Set();
|
||||
}
|
||||
@ -277,7 +260,7 @@ namespace SharedLibraryCore.RCon
|
||||
private void OnDataSent(object sender, SocketAsyncEventArgs e)
|
||||
{
|
||||
#if DEBUG == true
|
||||
Log.WriteDebug($"Sent {e.Buffer?.Length} bytes to {e.ConnectSocket?.RemoteEndPoint?.ToString()}");
|
||||
_log.WriteDebug($"Sent {e.Buffer?.Length} bytes to {e.ConnectSocket?.RemoteEndPoint?.ToString()}");
|
||||
#endif
|
||||
ActiveQueries[this.Endpoint].OnSentData.Set();
|
||||
}
|
@ -65,13 +65,13 @@ namespace IW4MAdmin.Application.RconParsers
|
||||
public bool CanGenerateLogPath { get; set; } = true;
|
||||
public string Name { get; set; } = "Call of Duty";
|
||||
|
||||
public async Task<string[]> ExecuteCommandAsync(Connection connection, string command)
|
||||
public async Task<string[]> ExecuteCommandAsync(IRConConnection connection, string command)
|
||||
{
|
||||
var response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, command);
|
||||
return response.Skip(1).ToArray();
|
||||
}
|
||||
|
||||
public async Task<Dvar<T>> GetDvarAsync<T>(Connection connection, string dvarName)
|
||||
public async Task<Dvar<T>> GetDvarAsync<T>(IRConConnection connection, string dvarName)
|
||||
{
|
||||
string[] lineSplit = await connection.SendQueryAsync(StaticHelpers.QueryType.GET_DVAR, dvarName);
|
||||
string response = string.Join('\n', lineSplit.Skip(1));
|
||||
@ -105,7 +105,7 @@ namespace IW4MAdmin.Application.RconParsers
|
||||
};
|
||||
}
|
||||
|
||||
public virtual async Task<(List<EFClient>, string)> GetStatusAsync(Connection connection)
|
||||
public virtual async Task<(List<EFClient>, string)> GetStatusAsync(IRConConnection connection)
|
||||
{
|
||||
string[] response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND_STATUS);
|
||||
#if DEBUG
|
||||
@ -132,7 +132,7 @@ namespace IW4MAdmin.Application.RconParsers
|
||||
return map;
|
||||
}
|
||||
|
||||
public async Task<bool> SetDvarAsync(Connection connection, string dvarName, object dvarValue)
|
||||
public async Task<bool> SetDvarAsync(IRConConnection connection, string dvarName, object dvarValue)
|
||||
{
|
||||
return (await connection.SendQueryAsync(StaticHelpers.QueryType.SET_DVAR, $"{dvarName} {dvarValue}")).Length > 0;
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{26E8
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8C8F3945-0AEF-4949-A1F7-B18E952E50BC}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
GameFiles\IW4x\userraw\_commands.gsc = GameFiles\IW4x\userraw\_commands.gsc
|
||||
GameFiles\IW4x\userraw\_customcallbacks.gsc = GameFiles\IW4x\userraw\_customcallbacks.gsc
|
||||
GameFiles\IW4x\userraw\scripts\_commands.gsc = GameFiles\IW4x\userraw\scripts\_commands.gsc
|
||||
GameFiles\IW4x\userraw\scripts\_customcallbacks.gsc = GameFiles\IW4x\userraw\scripts\_customcallbacks.gsc
|
||||
azure-pipelines.yml = azure-pipelines.yml
|
||||
PostPublish.ps1 = PostPublish.ps1
|
||||
README.md = README.md
|
||||
@ -57,6 +57,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutomessageFeed", "Plugins\
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiveRadar", "Plugins\LiveRadar\LiveRadar.csproj", "{00A1FED2-2254-4AF7-A5DB-2357FA7C88CD}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3065279E-17F0-4CE0-AF5B-014E04263D77}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationTests", "Tests\ApplicationTests\ApplicationTests.csproj", "{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -405,6 +409,29 @@ Global
|
||||
{00A1FED2-2254-4AF7-A5DB-2357FA7C88CD}.Release|x64.Build.0 = Release|Any CPU
|
||||
{00A1FED2-2254-4AF7-A5DB-2357FA7C88CD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{00A1FED2-2254-4AF7-A5DB-2357FA7C88CD}.Release|x86.Build.0 = Release|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Prerelease|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Prerelease|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Prerelease|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Prerelease|x64.ActiveCfg = Debug|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Prerelease|x64.Build.0 = Debug|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Prerelease|x86.ActiveCfg = Debug|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Prerelease|x86.Build.0 = Debug|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -421,6 +448,7 @@ Global
|
||||
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B} = {A848FCF1-8527-4AA8-A1AA-50D29695C678}
|
||||
{F5815359-CFC7-44B4-9A3B-C04BACAD5836} = {26E8B310-269E-46D4-A612-24601F16065F}
|
||||
{00A1FED2-2254-4AF7-A5DB-2357FA7C88CD} = {26E8B310-269E-46D4-A612-24601F16065F}
|
||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B} = {3065279E-17F0-4CE0-AF5B-014E04263D77}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {84F8F8E0-1F73-41E0-BD8D-BB6676E2EE87}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SyndicationFeed.ReaderWriter" Version="1.0.2" />
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.6" PrivateAssets="All" />
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.7" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
|
@ -20,14 +20,19 @@ namespace AutomessageFeed
|
||||
|
||||
public string Author => "RaidMax";
|
||||
|
||||
private Configuration _configuration;
|
||||
private int _currentFeedItem;
|
||||
private readonly IConfigurationHandler<Configuration> _configurationHandler;
|
||||
|
||||
public Plugin(IConfigurationHandlerFactory configurationHandlerFactory)
|
||||
{
|
||||
_configurationHandler = configurationHandlerFactory.GetConfigurationHandler<Configuration>("AutomessageFeedPluginSettings");
|
||||
}
|
||||
|
||||
private async Task<string> GetNextFeedItem(Server server)
|
||||
{
|
||||
var items = new List<string>();
|
||||
|
||||
using (var reader = XmlReader.Create(_configuration.FeedUrl, new XmlReaderSettings() { Async = true }))
|
||||
using (var reader = XmlReader.Create(_configurationHandler.Configuration().FeedUrl, new XmlReaderSettings() { Async = true }))
|
||||
{
|
||||
var feedReader = new RssFeedReader(reader);
|
||||
|
||||
@ -43,7 +48,7 @@ namespace AutomessageFeed
|
||||
}
|
||||
}
|
||||
|
||||
if (_currentFeedItem < items.Count && (_configuration.MaxFeedItems == 0 || _currentFeedItem < _configuration.MaxFeedItems))
|
||||
if (_currentFeedItem < items.Count && (_configurationHandler.Configuration().MaxFeedItems == 0 || _currentFeedItem < _configurationHandler.Configuration().MaxFeedItems))
|
||||
{
|
||||
_currentFeedItem++;
|
||||
return items[_currentFeedItem - 1];
|
||||
@ -60,15 +65,12 @@ namespace AutomessageFeed
|
||||
|
||||
public async Task OnLoadAsync(IManager manager)
|
||||
{
|
||||
var cfg = new BaseConfigurationHandler<Configuration>("AutomessageFeedPluginSettings");
|
||||
if (cfg.Configuration() == null)
|
||||
if (_configurationHandler.Configuration() == null)
|
||||
{
|
||||
cfg.Set((Configuration)new Configuration().Generate());
|
||||
await cfg.Save();
|
||||
_configurationHandler.Set((Configuration)new Configuration().Generate());
|
||||
await _configurationHandler.Save();
|
||||
}
|
||||
|
||||
_configuration = cfg.Configuration();
|
||||
|
||||
manager.GetMessageTokens().Add(new MessageToken("FEED", GetNextFeedItem));
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.6" PrivateAssets="All" />
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.7" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using LiveRadar.Configuration;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Dtos;
|
||||
@ -16,10 +17,12 @@ namespace LiveRadar.Web.Controllers
|
||||
};
|
||||
|
||||
private readonly IManager _manager;
|
||||
private readonly LiveRadarConfiguration _config;
|
||||
|
||||
public RadarController(IManager manager) : base(manager)
|
||||
public RadarController(IManager manager, IConfigurationHandlerFactory configurationHandlerFactory) : base(manager)
|
||||
{
|
||||
_manager = manager;
|
||||
_config = configurationHandlerFactory.GetConfigurationHandler<LiveRadarConfiguration>("LiveRadarConfiguration").Configuration() ?? new LiveRadarConfiguration();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
@ -45,7 +48,7 @@ namespace LiveRadar.Web.Controllers
|
||||
public IActionResult Map(long? serverId = null)
|
||||
{
|
||||
var server = serverId == null ? _manager.GetServers().FirstOrDefault() : _manager.GetServers().FirstOrDefault(_server => _server.EndPoint == serverId);
|
||||
var map = Plugin.Config.Configuration().Maps.FirstOrDefault(_map => _map.Name == server.CurrentMap.Name);
|
||||
var map = _config.Maps.FirstOrDefault(_map => _map.Name == server.CurrentMap.Name);
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
|
@ -16,7 +16,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.6" PrivateAssets="All" />
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.7" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -16,7 +16,12 @@ namespace LiveRadar
|
||||
|
||||
public string Author => "RaidMax";
|
||||
|
||||
internal static BaseConfigurationHandler<LiveRadarConfiguration> Config;
|
||||
private readonly IConfigurationHandler<LiveRadarConfiguration> _configurationHandler;
|
||||
|
||||
public Plugin(IConfigurationHandlerFactory configurationHandlerFactory)
|
||||
{
|
||||
_configurationHandler = configurationHandlerFactory.GetConfigurationHandler<LiveRadarConfiguration>("LiveRadarConfiguration");
|
||||
}
|
||||
|
||||
public Task OnEventAsync(GameEvent E, Server S)
|
||||
{
|
||||
@ -36,7 +41,7 @@ namespace LiveRadar
|
||||
}
|
||||
}
|
||||
|
||||
catch(Exception e)
|
||||
catch (Exception e)
|
||||
{
|
||||
S.Logger.WriteWarning($"Could not parse live radar output: {e.Data}");
|
||||
S.Logger.WriteDebug(e.GetExceptionInfo());
|
||||
@ -49,12 +54,10 @@ namespace LiveRadar
|
||||
|
||||
public async Task OnLoadAsync(IManager manager)
|
||||
{
|
||||
// load custom configuration
|
||||
Config = new BaseConfigurationHandler<LiveRadarConfiguration>("LiveRadarConfiguration");
|
||||
if (Config.Configuration() == null)
|
||||
if (_configurationHandler.Configuration() == null)
|
||||
{
|
||||
Config.Set((LiveRadarConfiguration)new LiveRadarConfiguration().Generate());
|
||||
await Config.Save();
|
||||
_configurationHandler.Set((LiveRadarConfiguration)new LiveRadarConfiguration().Generate());
|
||||
await _configurationHandler.Save();
|
||||
}
|
||||
|
||||
manager.GetPageList().Pages.Add(Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_RADAR_TITLE"], "/Radar/All");
|
||||
|
@ -23,7 +23,7 @@
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.6" PrivateAssets="All" />
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.7" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -4,7 +4,6 @@ using System.Threading.Tasks;
|
||||
using IW4MAdmin.Plugins.Login.Commands;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Commands;
|
||||
using SharedLibraryCore.Configuration;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using SharedLibraryCore.Exceptions;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
@ -20,11 +19,16 @@ namespace IW4MAdmin.Plugins.Login
|
||||
public string Author => "RaidMax";
|
||||
|
||||
public static ConcurrentDictionary<int, bool> AuthorizedClients { get; private set; }
|
||||
private Configuration Config;
|
||||
private readonly IConfigurationHandler<Configuration> _configHandler;
|
||||
|
||||
public Plugin(IConfigurationHandlerFactory configurationHandlerFactory)
|
||||
{
|
||||
_configHandler = configurationHandlerFactory.GetConfigurationHandler<Configuration>("LoginPluginSettings");
|
||||
}
|
||||
|
||||
public Task OnEventAsync(GameEvent E, Server S)
|
||||
{
|
||||
if (E.IsRemote || Config.RequirePrivilegedClientLogin == false)
|
||||
if (E.IsRemote || _configHandler.Configuration().RequirePrivilegedClientLogin == false)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (E.Type == GameEvent.EventType.Connect)
|
||||
@ -72,14 +76,11 @@ namespace IW4MAdmin.Plugins.Login
|
||||
{
|
||||
AuthorizedClients = new ConcurrentDictionary<int, bool>();
|
||||
|
||||
var cfg = new BaseConfigurationHandler<Configuration>("LoginPluginSettings");
|
||||
if (cfg.Configuration() == null)
|
||||
if (_configHandler.Configuration() == null)
|
||||
{
|
||||
cfg.Set((Configuration)new Configuration().Generate());
|
||||
await cfg.Save();
|
||||
_configHandler.Set((Configuration)new Configuration().Generate());
|
||||
await _configHandler.Save();
|
||||
}
|
||||
|
||||
Config = cfg.Configuration();
|
||||
}
|
||||
|
||||
public Task OnTickAsync(Server S) => Task.CompletedTask;
|
||||
|
@ -17,18 +17,23 @@ namespace IW4MAdmin.Plugins.ProfanityDeterment
|
||||
|
||||
public string Author => "RaidMax";
|
||||
|
||||
BaseConfigurationHandler<Configuration> Settings;
|
||||
private readonly IConfigurationHandler<Configuration> _configHandler;
|
||||
|
||||
public Plugin(IConfigurationHandlerFactory configurationHandlerFactory)
|
||||
{
|
||||
_configHandler = configurationHandlerFactory.GetConfigurationHandler<Configuration>("ProfanityDetermentSettings");
|
||||
}
|
||||
|
||||
public Task OnEventAsync(GameEvent E, Server S)
|
||||
{
|
||||
if (!Settings.Configuration().EnableProfanityDeterment)
|
||||
if (!_configHandler.Configuration().EnableProfanityDeterment)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (E.Type == GameEvent.EventType.Connect)
|
||||
{
|
||||
E.Origin.SetAdditionalProperty("_profanityInfringements", 0);
|
||||
|
||||
var objectionalWords = Settings.Configuration().OffensiveWords;
|
||||
var objectionalWords = _configHandler.Configuration().OffensiveWords;
|
||||
var matchedFilters = new List<string>();
|
||||
bool containsObjectionalWord = false;
|
||||
|
||||
@ -51,7 +56,7 @@ namespace IW4MAdmin.Plugins.ProfanityDeterment
|
||||
AutomatedOffense = $"{E.Origin.Name} - {string.Join(",", matchedFilters)}"
|
||||
}
|
||||
};
|
||||
E.Origin.Kick(Settings.Configuration().ProfanityKickMessage, sender);
|
||||
E.Origin.Kick(_configHandler.Configuration().ProfanityKickMessage, sender);
|
||||
};
|
||||
}
|
||||
|
||||
@ -62,7 +67,7 @@ namespace IW4MAdmin.Plugins.ProfanityDeterment
|
||||
|
||||
if (E.Type == GameEvent.EventType.Say)
|
||||
{
|
||||
var objectionalWords = Settings.Configuration().OffensiveWords;
|
||||
var objectionalWords = _configHandler.Configuration().OffensiveWords;
|
||||
bool containsObjectionalWord = false;
|
||||
var matchedFilters = new List<string>();
|
||||
|
||||
@ -88,15 +93,15 @@ namespace IW4MAdmin.Plugins.ProfanityDeterment
|
||||
}
|
||||
};
|
||||
|
||||
if (profanityInfringments >= Settings.Configuration().KickAfterInfringementCount)
|
||||
if (profanityInfringments >= _configHandler.Configuration().KickAfterInfringementCount)
|
||||
{
|
||||
E.Origin.Kick(Settings.Configuration().ProfanityKickMessage, sender);
|
||||
E.Origin.Kick(_configHandler.Configuration().ProfanityKickMessage, sender);
|
||||
}
|
||||
|
||||
else if (profanityInfringments < Settings.Configuration().KickAfterInfringementCount)
|
||||
else if (profanityInfringments < _configHandler.Configuration().KickAfterInfringementCount)
|
||||
{
|
||||
E.Origin.SetAdditionalProperty("_profanityInfringements", profanityInfringments + 1);
|
||||
E.Origin.Warn(Settings.Configuration().ProfanityWarningMessage, sender);
|
||||
E.Origin.Warn(_configHandler.Configuration().ProfanityWarningMessage, sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -105,12 +110,10 @@ namespace IW4MAdmin.Plugins.ProfanityDeterment
|
||||
|
||||
public async Task OnLoadAsync(IManager manager)
|
||||
{
|
||||
// load custom configuration
|
||||
Settings = new BaseConfigurationHandler<Configuration>("ProfanityDetermentSettings");
|
||||
if (Settings.Configuration() == null)
|
||||
if (_configHandler.Configuration() == null)
|
||||
{
|
||||
Settings.Set((Configuration)new Configuration().Generate());
|
||||
await Settings.Save();
|
||||
_configHandler.Set((Configuration)new Configuration().Generate());
|
||||
await _configHandler.Save();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.6" PrivateAssets="All" />
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.7" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
|
@ -17,7 +17,7 @@ namespace IW4MAdmin.Plugins.Stats.Config
|
||||
public IDictionary<DetectionType, DistributionConfiguration> DetectionDistributions { get; set; }
|
||||
public IDictionary<long, DetectionType[]> ServerDetectionTypes { get; set; }
|
||||
|
||||
public string Name() => "Stats";
|
||||
public string Name() => "StatsPluginSettings";
|
||||
public IBaseConfiguration Generate()
|
||||
{
|
||||
EnableAntiCheat = Utilities.PromptBool(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_SETUP_ENABLEAC"]);
|
||||
|
@ -21,8 +21,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
var killstreakMessage = Plugin.Config.Configuration().KillstreakMessages;
|
||||
var deathstreakMessage = Plugin.Config.Configuration().DeathstreakMessages;
|
||||
|
||||
string message = killstreakMessage.FirstOrDefault(m => m.Count == killStreak)?.Message;
|
||||
message = message ?? deathstreakMessage.FirstOrDefault(m => m.Count == deathStreak)?.Message;
|
||||
string message = killstreakMessage?.FirstOrDefault(m => m.Count == killStreak)?.Message;
|
||||
message = message ?? deathstreakMessage?.FirstOrDefault(m => m.Count == deathStreak)?.Message;
|
||||
return message ?? "";
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ using IW4MAdmin.Plugins.Stats.Helpers;
|
||||
using IW4MAdmin.Plugins.Stats.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Configuration;
|
||||
using SharedLibraryCore.Database;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using SharedLibraryCore.Dtos;
|
||||
@ -13,7 +12,6 @@ using SharedLibraryCore.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IW4MAdmin.Plugins.Stats
|
||||
@ -28,12 +26,17 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
|
||||
public static StatManager Manager { get; private set; }
|
||||
public static IManager ServerManager;
|
||||
public static BaseConfigurationHandler<StatsConfiguration> Config { get; private set; }
|
||||
public static IConfigurationHandler<StatsConfiguration> Config { get; private set; }
|
||||
#if DEBUG
|
||||
int scriptDamageCount;
|
||||
int scriptKillCount;
|
||||
#endif
|
||||
|
||||
public Plugin(IConfigurationHandlerFactory configurationHandlerFactory)
|
||||
{
|
||||
Config = configurationHandlerFactory.GetConfigurationHandler<StatsConfiguration>("StatsPluginSettings");
|
||||
}
|
||||
|
||||
public async Task OnEventAsync(GameEvent E, Server S)
|
||||
{
|
||||
switch (E.Type)
|
||||
@ -53,16 +56,16 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
if (!string.IsNullOrEmpty(E.Data) &&
|
||||
E.Origin.ClientId > 1)
|
||||
{
|
||||
await Manager.AddMessageAsync(E.Origin.ClientId, StatManager.GetIdForServer(E.Owner), E.Data);
|
||||
await Manager.AddMessageAsync(E.Origin.ClientId, StatManager.GetIdForServer(S), E.Data);
|
||||
}
|
||||
break;
|
||||
case GameEvent.EventType.MapChange:
|
||||
Manager.SetTeamBased(StatManager.GetIdForServer(E.Owner), E.Owner.Gametype != "dm");
|
||||
Manager.ResetKillstreaks(E.Owner);
|
||||
await Manager.Sync(E.Owner);
|
||||
Manager.SetTeamBased(StatManager.GetIdForServer(S), S.Gametype != "dm");
|
||||
Manager.ResetKillstreaks(S);
|
||||
await Manager.Sync(S);
|
||||
break;
|
||||
case GameEvent.EventType.MapEnd:
|
||||
await Manager.Sync(E.Owner);
|
||||
await Manager.Sync(S);
|
||||
break;
|
||||
case GameEvent.EventType.JoinTeam:
|
||||
break;
|
||||
@ -82,7 +85,7 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
break;
|
||||
case GameEvent.EventType.ScriptKill:
|
||||
string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
|
||||
if ((E.Owner.CustomCallback || ShouldOverrideAnticheatSetting(E.Owner)) && killInfo.Length >= 18 && !ShouldIgnoreEvent(E.Origin, E.Target))
|
||||
if ((S.CustomCallback || ShouldOverrideAnticheatSetting(S)) && killInfo.Length >= 18 && !ShouldIgnoreEvent(E.Origin, E.Target))
|
||||
{
|
||||
// this treats "world" damage as self damage
|
||||
if (IsWorldDamage(E.Origin))
|
||||
@ -95,7 +98,7 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
S.Logger.WriteInfo($"Start ScriptKill {scriptKillCount}");
|
||||
#endif
|
||||
|
||||
await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
||||
await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, StatManager.GetIdForServer(S), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
||||
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15], killInfo[16], killInfo[17]);
|
||||
|
||||
#if DEBUG
|
||||
@ -105,7 +108,7 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
|
||||
else
|
||||
{
|
||||
E.Owner.Logger.WriteDebug("Skipping script kill as it is ignored or data in customcallbacks is outdated/missing");
|
||||
S.Logger.WriteDebug("Skipping script kill as it is ignored or data in customcallbacks is outdated/missing");
|
||||
}
|
||||
break;
|
||||
case GameEvent.EventType.Kill:
|
||||
@ -129,12 +132,12 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
E.Origin = E.Target;
|
||||
}
|
||||
|
||||
Manager.AddDamageEvent(E.Data, E.Origin.ClientId, E.Target.ClientId, StatManager.GetIdForServer(E.Owner));
|
||||
Manager.AddDamageEvent(E.Data, E.Origin.ClientId, E.Target.ClientId, StatManager.GetIdForServer(S));
|
||||
}
|
||||
break;
|
||||
case GameEvent.EventType.ScriptDamage:
|
||||
killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
|
||||
if ((E.Owner.CustomCallback || ShouldOverrideAnticheatSetting(E.Owner)) && killInfo.Length >= 18 && !ShouldIgnoreEvent(E.Origin, E.Target))
|
||||
if ((S.CustomCallback || ShouldOverrideAnticheatSetting(S)) && killInfo.Length >= 18 && !ShouldIgnoreEvent(E.Origin, E.Target))
|
||||
{
|
||||
// this treats "world" damage as self damage
|
||||
if (IsWorldDamage(E.Origin))
|
||||
@ -147,7 +150,7 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
S.Logger.WriteInfo($"Start ScriptDamage {scriptDamageCount}");
|
||||
#endif
|
||||
|
||||
await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
||||
await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, StatManager.GetIdForServer(S), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
||||
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15], killInfo[16], killInfo[17]);
|
||||
|
||||
#if DEBUG
|
||||
@ -157,7 +160,7 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
|
||||
else
|
||||
{
|
||||
E.Owner.Logger.WriteDebug("Skipping script damage as it is ignored or data in customcallbacks is outdated/missing");
|
||||
S.Logger.WriteDebug("Skipping script damage as it is ignored or data in customcallbacks is outdated/missing");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -166,7 +169,6 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
public async Task OnLoadAsync(IManager manager)
|
||||
{
|
||||
// load custom configuration
|
||||
Config = new BaseConfigurationHandler<StatsConfiguration>("StatsPluginSettings");
|
||||
if (Config.Configuration() == null)
|
||||
{
|
||||
Config.Set((StatsConfiguration)new StatsConfiguration().Generate());
|
||||
@ -518,7 +520,7 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
/// <returns></returns>
|
||||
private bool ShouldIgnoreEvent(EFClient origin, EFClient target)
|
||||
{
|
||||
return ((origin?.NetworkId == 1 && target?.NetworkId == 1) || (origin?.ClientId <= 1 && target?.ClientId <= 1));
|
||||
return ((origin?.NetworkId == 1 && target?.NetworkId == 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -16,7 +16,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.6" PrivateAssets="All" />
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.7" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
|
@ -1,4 +1,5 @@
|
||||
using IW4MAdmin.Application;
|
||||
using IW4MAdmin.Application.Misc;
|
||||
using SharedLibraryCore.Configuration;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using SharedLibraryCore.RCon;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -14,7 +15,7 @@ namespace Tests
|
||||
|
||||
public override string Version => "test";
|
||||
|
||||
public override async Task<(List<EFClient>, string)> GetStatusAsync(Connection connection)
|
||||
public override async Task<(List<EFClient>, string)> GetStatusAsync(IRConConnection connection)
|
||||
{
|
||||
var clientList = new List<EFClient>();
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.6" PrivateAssets="All" />
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.7" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -64,16 +64,19 @@ namespace IW4MAdmin.Plugins.Welcome
|
||||
|
||||
public string Name => "Welcome Plugin";
|
||||
|
||||
private BaseConfigurationHandler<WelcomeConfiguration> Config;
|
||||
private readonly IConfigurationHandler<WelcomeConfiguration> _configHandler;
|
||||
|
||||
public Plugin(IConfigurationHandlerFactory configurationHandlerFactory)
|
||||
{
|
||||
_configHandler = configurationHandlerFactory.GetConfigurationHandler<WelcomeConfiguration>("WelcomePluginSettings");
|
||||
}
|
||||
|
||||
public async Task OnLoadAsync(IManager manager)
|
||||
{
|
||||
// load custom configuration
|
||||
Config = new BaseConfigurationHandler<WelcomeConfiguration>("WelcomePluginSettings");
|
||||
if (Config.Configuration() == null)
|
||||
if (_configHandler.Configuration() == null)
|
||||
{
|
||||
Config.Set((WelcomeConfiguration)new WelcomeConfiguration().Generate());
|
||||
await Config.Save();
|
||||
_configHandler.Set((WelcomeConfiguration)new WelcomeConfiguration().Generate());
|
||||
await _configHandler.Save();
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,9 +90,9 @@ namespace IW4MAdmin.Plugins.Welcome
|
||||
{
|
||||
EFClient newPlayer = E.Origin;
|
||||
if (newPlayer.Level >= Permission.Trusted && !E.Origin.Masked)
|
||||
E.Owner.Broadcast(await ProcessAnnouncement(Config.Configuration().PrivilegedAnnouncementMessage, newPlayer));
|
||||
E.Owner.Broadcast(await ProcessAnnouncement(_configHandler.Configuration().PrivilegedAnnouncementMessage, newPlayer));
|
||||
|
||||
newPlayer.Tell(await ProcessAnnouncement(Config.Configuration().UserWelcomeMessage, newPlayer));
|
||||
newPlayer.Tell(await ProcessAnnouncement(_configHandler.Configuration().UserWelcomeMessage, newPlayer));
|
||||
|
||||
if (newPlayer.Level == Permission.Flagged)
|
||||
{
|
||||
@ -107,7 +110,7 @@ namespace IW4MAdmin.Plugins.Welcome
|
||||
E.Owner.ToAdmins($"^1NOTICE: ^7Flagged player ^5{newPlayer.Name} ^7({penaltyReason}) has joined!");
|
||||
}
|
||||
else
|
||||
E.Owner.Broadcast(await ProcessAnnouncement(Config.Configuration().UserAnnouncementMessage, newPlayer));
|
||||
E.Owner.Broadcast(await ProcessAnnouncement(_configHandler.Configuration().UserAnnouncementMessage, newPlayer));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.6" PrivateAssets="All" />
|
||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.7" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
|
@ -500,18 +500,18 @@ namespace SharedLibraryCore.Commands
|
||||
|
||||
public override Task ExecuteAsync(GameEvent E)
|
||||
{
|
||||
String cmd = E.Data.Trim();
|
||||
string cmd = E.Data.Trim();
|
||||
|
||||
if (cmd.Length > 2)
|
||||
{
|
||||
bool found = false;
|
||||
foreach (Command C in E.Owner.Manager.GetCommands())
|
||||
foreach (var command in E.Owner.Manager.GetCommands())
|
||||
{
|
||||
if (C.Name == cmd.ToLower() ||
|
||||
C.Alias == cmd.ToLower())
|
||||
if (command.Name == cmd.ToLower() ||
|
||||
command.Alias == cmd.ToLower())
|
||||
{
|
||||
E.Origin.Tell($"[^3{C.Name}^7] {C.Description}");
|
||||
E.Origin.Tell(C.Syntax);
|
||||
E.Origin.Tell($"[^3{command.Name}^7] {command.Description}");
|
||||
E.Origin.Tell(command.Syntax);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
@ -56,11 +56,11 @@ namespace SharedLibraryCore.Configuration
|
||||
{
|
||||
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
||||
var parserVersions = rconParsers.Select(_parser => _parser.Name).ToArray();
|
||||
var selection = Utilities.PromptSelection($"{loc["SETUP_SERVER_RCON_PARSER_VERSION"]} ({IPAddress}:{Port})", $"{loc["SETUP_PROMPT_DEFAULT"]} (Call of Duty)", null, parserVersions);
|
||||
var selection = Utilities.PromptSelection($"{loc["SETUP_SERVER_RCON_PARSER_VERSION"]} ({IPAddress}:{Port})", parserVersions[0], null, parserVersions);
|
||||
|
||||
if (selection.Item1 >= 0)
|
||||
{
|
||||
RConParserVersion = rconParsers.First(_parser => _parser.Name == selection.Item2).Version;
|
||||
RConParserVersion = rconParsers.FirstOrDefault(_parser => _parser.Name == selection.Item2)?.Version;
|
||||
|
||||
if (selection.Item1 > 0 && !rconParsers[selection.Item1 - 1].CanGenerateLogPath)
|
||||
{
|
||||
@ -70,11 +70,11 @@ namespace SharedLibraryCore.Configuration
|
||||
}
|
||||
|
||||
parserVersions = eventParsers.Select(_parser => _parser.Name).ToArray();
|
||||
selection = Utilities.PromptSelection($"{loc["SETUP_SERVER_EVENT_PARSER_VERSION"]} ({IPAddress}:{Port})", $"{loc["SETUP_PROMPT_DEFAULT"]} (Call of Duty)", null, parserVersions);
|
||||
selection = Utilities.PromptSelection($"{loc["SETUP_SERVER_EVENT_PARSER_VERSION"]} ({IPAddress}:{Port})", parserVersions[0], null, parserVersions);
|
||||
|
||||
if (selection.Item1 >= 0)
|
||||
{
|
||||
EventParserVersion = eventParsers.First(_parser => _parser.Name == selection.Item2).Version;
|
||||
EventParserVersion = eventParsers.FirstOrDefault(_parser => _parser.Name == selection.Item2)?.Version;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,12 +26,6 @@ namespace SharedLibraryCore.Configuration.Validation
|
||||
RuleForEach(_server => _server.AutoMessages)
|
||||
.NotEmpty();
|
||||
|
||||
RuleFor(_server => _server.RConParserVersion)
|
||||
.NotEmpty();
|
||||
|
||||
RuleFor(_server => _server.EventParserVersion)
|
||||
.NotEmpty();
|
||||
|
||||
RuleFor(_server => _server.ReservedSlotNumber)
|
||||
.InclusiveBetween(0, 32);
|
||||
}
|
||||
|
14
SharedLibraryCore/Interfaces/IBasePathProvider.cs
Normal file
14
SharedLibraryCore/Interfaces/IBasePathProvider.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace SharedLibraryCore.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// defines the capabilities for providing a base path
|
||||
/// unused as of now, will be used later during refactorying
|
||||
/// </summary>
|
||||
public interface IBasePathProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// working directory of IW4MAdmin
|
||||
/// </summary>
|
||||
string BasePath { get; }
|
||||
}
|
||||
}
|
17
SharedLibraryCore/Interfaces/IConfigurationHandlerFactory.cs
Normal file
17
SharedLibraryCore/Interfaces/IConfigurationHandlerFactory.cs
Normal file
@ -0,0 +1,17 @@
|
||||
namespace SharedLibraryCore.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// defines the capabilities of the configuration handler factory
|
||||
/// used to generate new instance of configuration handlers
|
||||
/// </summary>
|
||||
public interface IConfigurationHandlerFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// generates a new configuration handler
|
||||
/// </summary>
|
||||
/// <typeparam name="T">base configuration type</typeparam>
|
||||
/// <param name="name">file name of configuration</param>
|
||||
/// <returns>new configuration handler instance</returns>
|
||||
IConfigurationHandler<T> GetConfigurationHandler<T>(string name) where T : IBaseConfiguration;
|
||||
}
|
||||
}
|
18
SharedLibraryCore/Interfaces/IGameServerInstanceFactory.cs
Normal file
18
SharedLibraryCore/Interfaces/IGameServerInstanceFactory.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using SharedLibraryCore.Configuration;
|
||||
|
||||
namespace SharedLibraryCore.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// defines the capabilities of game server instance factory
|
||||
/// </summary>
|
||||
public interface IGameServerInstanceFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// creates the instance of a game server
|
||||
/// </summary>
|
||||
/// <param name="config">server configuration</param>
|
||||
/// <param name="manager">application manager</param>
|
||||
/// <returns></returns>
|
||||
Server CreateServer(ServerConfiguration config, IManager manager);
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
using System.Threading.Tasks;
|
||||
using SharedLibraryCore.Services;
|
||||
using SharedLibraryCore.Configuration;
|
||||
using System.Reflection;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using System.Threading;
|
||||
using System.Collections;
|
||||
@ -29,7 +28,10 @@ namespace SharedLibraryCore.Interfaces
|
||||
/// </summary>
|
||||
/// <returns>EventHandler for the manager</returns>
|
||||
IEventHandler GetEventHandler();
|
||||
IList<Assembly> GetPluginAssemblies();
|
||||
/// <summary>
|
||||
/// enumerates the registered plugin instances
|
||||
/// </summary>
|
||||
IEnumerable<IPlugin> Plugins { get; }
|
||||
/// <summary>
|
||||
/// provides a page list to add and remove from
|
||||
/// </summary>
|
||||
|
@ -1,32 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace SharedLibraryCore.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the capabilities of the plugin importer
|
||||
/// defines the capabilities of the plugin importer
|
||||
/// </summary>
|
||||
public interface IPluginImporter
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// Command types that are defined in plugin assemblies
|
||||
/// discovers C# assembly plugin and command types
|
||||
/// </summary>
|
||||
IList<Type> CommandTypes { get; }
|
||||
/// <returns>tuple of IPlugin implementation type definitions, and IManagerCommand type definitions</returns>
|
||||
(IEnumerable<Type>, IEnumerable<Type>) DiscoverAssemblyPluginImplementations();
|
||||
|
||||
/// <summary>
|
||||
/// The loaded plugins from plugin assemblies
|
||||
/// discovers the script plugins
|
||||
/// </summary>
|
||||
IList<IPlugin> ActivePlugins { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Assemblies that contain plugins
|
||||
/// </summary>
|
||||
IList<Assembly> PluginAssemblies { get; }
|
||||
|
||||
/// <summary>
|
||||
/// All assemblies in the plugin folder
|
||||
/// </summary>
|
||||
IList<Assembly> Assemblies { get; }
|
||||
/// <returns>initialized script plugin collection</returns>
|
||||
IEnumerable<IPlugin> DiscoverScriptPlugins();
|
||||
}
|
||||
}
|
||||
|
25
SharedLibraryCore/Interfaces/IRConConnection.cs
Normal file
25
SharedLibraryCore/Interfaces/IRConConnection.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using SharedLibraryCore.RCon;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibraryCore.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// defines the capabilities of an RCon connection
|
||||
/// </summary>
|
||||
public interface IRConConnection
|
||||
{
|
||||
/// <summary>
|
||||
/// sends a query with the instance of the rcon connection
|
||||
/// </summary>
|
||||
/// <param name="type">type of RCon query to perform</param>
|
||||
/// <param name="parameters">optional parameter list</param>
|
||||
/// <returns></returns>
|
||||
Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "");
|
||||
|
||||
/// <summary>
|
||||
/// sets the rcon parser configuration
|
||||
/// </summary>
|
||||
/// <param name="config">parser config</param>
|
||||
void SetConfiguration(IRConParserConfiguration config);
|
||||
}
|
||||
}
|
17
SharedLibraryCore/Interfaces/IRConConnectionFactory.cs
Normal file
17
SharedLibraryCore/Interfaces/IRConConnectionFactory.cs
Normal file
@ -0,0 +1,17 @@
|
||||
namespace SharedLibraryCore.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// defines the capabilities of an RCon connection factory
|
||||
/// </summary>
|
||||
public interface IRConConnectionFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// creates an rcon connection instance
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">ip address of the server</param>
|
||||
/// <param name="port">port of the server</param>
|
||||
/// <param name="password"> password of the server</param>
|
||||
/// <returns>instance of rcon connection</returns>
|
||||
IRConConnection CreateConnection(string ipAddress, int port, string password);
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using SharedLibraryCore.RCon;
|
||||
using static SharedLibraryCore.Server;
|
||||
|
||||
namespace SharedLibraryCore.Interfaces
|
||||
@ -15,7 +14,7 @@ namespace SharedLibraryCore.Interfaces
|
||||
/// <param name="connection">RCon connection to retrieve with</param>
|
||||
/// <param name="dvarName">name of DVAR</param>
|
||||
/// <returns></returns>
|
||||
Task<Dvar<T>> GetDvarAsync<T>(Connection connection, string dvarName);
|
||||
Task<Dvar<T>> GetDvarAsync<T>(IRConConnection connection, string dvarName);
|
||||
|
||||
/// <summary>
|
||||
/// set value of DVAR by name
|
||||
@ -24,7 +23,7 @@ namespace SharedLibraryCore.Interfaces
|
||||
/// <param name="dvarName">name of DVAR to set</param>
|
||||
/// <param name="dvarValue">value to set DVAR to</param>
|
||||
/// <returns></returns>
|
||||
Task<bool> SetDvarAsync(Connection connection, string dvarName, object dvarValue);
|
||||
Task<bool> SetDvarAsync(IRConConnection connection, string dvarName, object dvarValue);
|
||||
|
||||
/// <summary>
|
||||
/// executes a console command on the server
|
||||
@ -32,14 +31,14 @@ namespace SharedLibraryCore.Interfaces
|
||||
/// <param name="connection">RCon connection to use</param>
|
||||
/// <param name="command">console command to execute</param>
|
||||
/// <returns></returns>
|
||||
Task<string[]> ExecuteCommandAsync(Connection connection, string command);
|
||||
Task<string[]> ExecuteCommandAsync(IRConConnection connection, string command);
|
||||
|
||||
/// <summary>
|
||||
/// get the list of connected clients from status response
|
||||
/// </summary>
|
||||
/// <param name="connection">RCon connection to use</param>
|
||||
/// <returns>list of clients, and current map</returns>
|
||||
Task<(List<EFClient>, string)> GetStatusAsync(Connection connection);
|
||||
Task<(List<EFClient>, string)> GetStatusAsync(IRConConnection connection);
|
||||
|
||||
/// <summary>
|
||||
/// stores the RCon configuration
|
||||
|
@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SharedLibraryCore.RCon
|
||||
namespace SharedLibraryCore.RCon
|
||||
{
|
||||
public class CommandPrefix
|
||||
{
|
||||
|
@ -28,7 +28,7 @@ namespace SharedLibraryCore
|
||||
T7 = 8
|
||||
}
|
||||
|
||||
public Server(IManager mgr, ServerConfiguration config)
|
||||
public Server(IManager mgr, IRConConnectionFactory rconConnectionFactory, ServerConfiguration config)
|
||||
{
|
||||
Password = config.Password;
|
||||
IP = config.IPAddress;
|
||||
@ -37,8 +37,7 @@ namespace SharedLibraryCore
|
||||
Logger = Manager.GetLogger(this.EndPoint);
|
||||
Logger.WriteInfo(this.ToString());
|
||||
ServerConfig = config;
|
||||
RemoteConnection = new RCon.Connection(IP, Port, Password, Logger, null);
|
||||
|
||||
RemoteConnection = rconConnectionFactory.CreateConnection(IP, Port, Password);
|
||||
EventProcessing = new SemaphoreSlim(1, 1);
|
||||
Clients = new List<EFClient>(new EFClient[18]);
|
||||
Reports = new List<Report>();
|
||||
@ -283,7 +282,7 @@ namespace SharedLibraryCore
|
||||
public IManager Manager { get; protected set; }
|
||||
public ILogger Logger { get; private set; }
|
||||
public ServerConfiguration ServerConfig { get; private set; }
|
||||
public List<Map> Maps { get; protected set; }
|
||||
public List<Map> Maps { get; protected set; } = new List<Map>();
|
||||
public List<Report> Reports { get; set; }
|
||||
public List<ChatInfo> ChatHistory { get; protected set; }
|
||||
public Queue<PlayerHistory> ClientHistory { get; private set; }
|
||||
@ -307,7 +306,7 @@ namespace SharedLibraryCore
|
||||
public bool Throttled { get; protected set; }
|
||||
public bool CustomCallback { get; protected set; }
|
||||
public string WorkingDirectory { get; protected set; }
|
||||
public RCon.Connection RemoteConnection { get; protected set; }
|
||||
public IRConConnection RemoteConnection { get; protected set; }
|
||||
public IRConParser RconParser { get; protected set; }
|
||||
public IEventParser EventParser { get; set; }
|
||||
public string LogPath { get; protected set; }
|
||||
|
@ -6,7 +6,7 @@
|
||||
<ApplicationIcon />
|
||||
<StartupObject />
|
||||
<PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId>
|
||||
<Version>2.2.6</Version>
|
||||
<Version>2.2.7</Version>
|
||||
<Authors>RaidMax</Authors>
|
||||
<Company>Forever None</Company>
|
||||
<Configurations>Debug;Release;Prerelease</Configurations>
|
||||
@ -20,8 +20,8 @@
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<Description>Shared Library for IW4MAdmin</Description>
|
||||
<AssemblyVersion>2.2.6.0</AssemblyVersion>
|
||||
<FileVersion>2.2.6.0</FileVersion>
|
||||
<AssemblyVersion>2.2.7.0</AssemblyVersion>
|
||||
<FileVersion>2.2.7.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prerelease|AnyCPU'">
|
||||
@ -68,6 +68,10 @@
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.0" />
|
||||
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
||||
<Exec Command="if not exist "$(ProjectDir)..\BUILD" (
if $(ConfigurationName) == Debug (
md "$(ProjectDir)..\BUILD"
)
)
if not exist "$(ProjectDir)..\BUILD\Plugins" (
if $(ConfigurationName) == Debug (
md "$(ProjectDir)..\BUILD\Plugins"
)
)" />
|
||||
|
34
Tests/ApplicationTests/ApplicationTests.csproj
Normal file
34
Tests/ApplicationTests/ApplicationTests.csproj
Normal file
@ -0,0 +1,34 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FakeItEasy" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Application\Application.csproj" />
|
||||
<ProjectReference Include="..\..\Plugins\Stats\Stats.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Files\T6Game.log">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Files\T6GameStats.log">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Files\T6MapRotation.log">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
85
Tests/ApplicationTests/ServerTests.cs
Normal file
85
Tests/ApplicationTests/ServerTests.cs
Normal file
@ -0,0 +1,85 @@
|
||||
using FakeItEasy;
|
||||
using IW4MAdmin;
|
||||
using IW4MAdmin.Application;
|
||||
using IW4MAdmin.Application.EventParsers;
|
||||
using NUnit.Framework;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace ApplicationTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ServerTests
|
||||
{
|
||||
ILogger logger;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
logger = A.Fake<ILogger>();
|
||||
|
||||
void testLog(string msg) => Console.WriteLine(msg);
|
||||
|
||||
A.CallTo(() => logger.WriteError(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||
A.CallTo(() => logger.WriteWarning(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||
A.CallTo(() => logger.WriteInfo(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||
A.CallTo(() => logger.WriteDebug(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GameTimeFalseQuitTest()
|
||||
{
|
||||
var mgr = A.Fake<IManager>();
|
||||
var server = new IW4MServer(mgr,
|
||||
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
||||
A.Fake<ITranslationLookup>(), A.Fake<IRConConnectionFactory>());
|
||||
|
||||
var parser = new BaseEventParser();
|
||||
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
||||
|
||||
var log = System.IO.File.ReadAllLines("Files\\T6MapRotation.log");
|
||||
foreach (string line in log)
|
||||
{
|
||||
var e = parser.GenerateGameEvent(line);
|
||||
if (e.Origin != null)
|
||||
{
|
||||
e.Origin.CurrentServer = server;
|
||||
}
|
||||
|
||||
server.ExecuteEvent(e).Wait();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LogFileReplay()
|
||||
{
|
||||
var mgr = A.Fake<IManager>();
|
||||
A.CallTo(() => mgr.GetLogger(A<long>.Ignored)).Returns(logger);
|
||||
|
||||
var server = new IW4MServer(mgr,
|
||||
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
||||
A.Fake<ITranslationLookup>(), A.Fake<IRConConnectionFactory>());
|
||||
|
||||
var parser = new BaseEventParser();
|
||||
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
||||
|
||||
var log = System.IO.File.ReadAllLines("Files\\T6Game.log");
|
||||
long lastEventId = 0;
|
||||
foreach (string line in log)
|
||||
{
|
||||
var e = parser.GenerateGameEvent(line);
|
||||
server.Logger.WriteInfo($"{e.GameTime}");
|
||||
if (e.Origin != null)
|
||||
{
|
||||
e.Origin.CurrentServer = server;
|
||||
}
|
||||
|
||||
server.ExecuteEvent(e).Wait();
|
||||
lastEventId = e.Id;
|
||||
}
|
||||
|
||||
Assert.GreaterOrEqual(lastEventId, log.Length);
|
||||
}
|
||||
}
|
||||
}
|
117
Tests/ApplicationTests/StatsTests.cs
Normal file
117
Tests/ApplicationTests/StatsTests.cs
Normal file
@ -0,0 +1,117 @@
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using IW4MAdmin;
|
||||
using FakeItEasy;
|
||||
using IW4MAdmin.Application.EventParsers;
|
||||
using System.Linq;
|
||||
using IW4MAdmin.Plugins.Stats.Models;
|
||||
using IW4MAdmin.Application.Helpers;
|
||||
using IW4MAdmin.Plugins.Stats.Config;
|
||||
using System.Collections.Generic;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
|
||||
namespace ApplicationTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class StatsTests
|
||||
{
|
||||
ILogger logger;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
logger = A.Fake<ILogger>();
|
||||
|
||||
void testLog(string msg) => Console.WriteLine(msg);
|
||||
|
||||
A.CallTo(() => logger.WriteError(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||
A.CallTo(() => logger.WriteWarning(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||
A.CallTo(() => logger.WriteInfo(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||
A.CallTo(() => logger.WriteDebug(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestKDR()
|
||||
{
|
||||
var mgr = A.Fake<IManager>();
|
||||
var handlerFactory = A.Fake<IConfigurationHandlerFactory>();
|
||||
var config = A.Fake<IConfigurationHandler<StatsConfiguration>>();
|
||||
var plugin = new IW4MAdmin.Plugins.Stats.Plugin(handlerFactory);
|
||||
|
||||
A.CallTo(() => config.Configuration())
|
||||
.Returns(new StatsConfiguration()
|
||||
{
|
||||
EnableAntiCheat = true
|
||||
});
|
||||
|
||||
A.CallTo(() => handlerFactory.GetConfigurationHandler<StatsConfiguration>(A<string>.Ignored))
|
||||
.Returns(config);
|
||||
|
||||
A.CallTo(() => mgr.GetLogger(A<long>.Ignored))
|
||||
.Returns(logger);
|
||||
|
||||
var server = new IW4MServer(mgr,
|
||||
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
||||
A.Fake<ITranslationLookup>(),
|
||||
A.Fake<IRConConnectionFactory>());
|
||||
|
||||
var parser = new BaseEventParser();
|
||||
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
||||
|
||||
var log = System.IO.File.ReadAllLines("Files\\T6GameStats.log");
|
||||
plugin.OnLoadAsync(mgr).Wait();
|
||||
plugin.OnEventAsync(new SharedLibraryCore.GameEvent() { Type = SharedLibraryCore.GameEvent.EventType.Start, Owner = server }, server).Wait();
|
||||
|
||||
var clientList = new Dictionary<long, EFClient>();
|
||||
|
||||
foreach (string line in log)
|
||||
{
|
||||
var e = parser.GenerateGameEvent(line);
|
||||
if (e.Origin != null)
|
||||
{
|
||||
//if (!clientList.ContainsKey(e.Origin.NetworkId))
|
||||
//{
|
||||
// clientList.Add(e.Origin.NetworkId, e.Origin);
|
||||
//}
|
||||
|
||||
//else
|
||||
//{
|
||||
// e.Origin = clientList[e.Origin.NetworkId];
|
||||
//}
|
||||
|
||||
e.Origin = server.GetClientsAsList().FirstOrDefault(_client => _client.NetworkId == e.Origin.NetworkId) ?? e.Origin;
|
||||
e.Origin.CurrentServer = server;
|
||||
}
|
||||
|
||||
if (e.Target != null)
|
||||
{
|
||||
//if (!clientList.ContainsKey(e.Target.NetworkId))
|
||||
//{
|
||||
// clientList.Add(e.Target.NetworkId, e.Target);
|
||||
//}
|
||||
|
||||
//else
|
||||
//{
|
||||
// e.Target = clientList[e.Target.NetworkId];
|
||||
//}
|
||||
|
||||
e.Target = server.GetClientsAsList().FirstOrDefault(_client => _client.NetworkId == e.Target.NetworkId) ?? e.Target;
|
||||
e.Target.CurrentServer = server;
|
||||
}
|
||||
|
||||
server.ExecuteEvent(e).Wait();
|
||||
plugin.OnEventAsync(e, server).Wait();
|
||||
}
|
||||
|
||||
var client = server.GetClientsAsList().First(_client => _client?.NetworkId == 2028755667);
|
||||
var stats = client.GetAdditionalProperty<EFClientStatistics>("ClientStats");
|
||||
}
|
||||
|
||||
class BasePathProvider : IBasePathProvider
|
||||
{
|
||||
public string BasePath => @"X:\IW4MAdmin\BUILD\Plugins";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -11,11 +11,8 @@ namespace WebfrontCore.Controllers
|
||||
{
|
||||
public class HomeController : BaseController
|
||||
{
|
||||
private readonly IPluginImporter _pluginImporter;
|
||||
|
||||
public HomeController(IManager manager, IPluginImporter importer) : base(manager)
|
||||
public HomeController(IManager manager) : base(manager)
|
||||
{
|
||||
_pluginImporter = importer;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Index()
|
||||
@ -68,7 +65,7 @@ namespace WebfrontCore.Controllers
|
||||
var pluginType = _cmd.GetType().Assembly.GetTypes().FirstOrDefault(_type => _type.Assembly != excludedAssembly && typeof(IPlugin).IsAssignableFrom(_type));
|
||||
return pluginType == null ?
|
||||
Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_HELP_COMMAND_NATIVE"] :
|
||||
_pluginImporter.ActivePlugins.First(_plugin => _plugin.GetType() == pluginType).Name; // for now we're just returning the name of the plugin, maybe later we'll include more info
|
||||
Manager.Plugins.First(_plugin => _plugin.GetType() == pluginType).Name; // for now we're just returning the name of the plugin, maybe later we'll include more info
|
||||
})
|
||||
.Select(_grp => (_grp.Key, _grp.AsEnumerable()));
|
||||
|
||||
|
@ -7,9 +7,14 @@ using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Database;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using WebfrontCore.Middleware;
|
||||
|
||||
@ -32,20 +37,33 @@ namespace WebfrontCore
|
||||
});
|
||||
});
|
||||
|
||||
IEnumerable<Assembly> pluginAssemblies()
|
||||
{
|
||||
string pluginDir = $"{Utilities.OperatingDirectory}Plugins{Path.DirectorySeparatorChar}";
|
||||
|
||||
if (Directory.Exists(pluginDir))
|
||||
{
|
||||
var dllFileNames = Directory.GetFiles($"{Utilities.OperatingDirectory}Plugins{Path.DirectorySeparatorChar}", "*.dll");
|
||||
return dllFileNames.Select(_file => Assembly.LoadFrom(_file));
|
||||
}
|
||||
|
||||
return Enumerable.Empty<Assembly>();
|
||||
}
|
||||
|
||||
// Add framework services.
|
||||
var mvcBuilder = services.AddMvc(_options => _options.SuppressAsyncSuffixInActionNames = false)
|
||||
.ConfigureApplicationPartManager(_ =>
|
||||
.ConfigureApplicationPartManager(_partManager =>
|
||||
{
|
||||
foreach (var assembly in Program.Manager.GetPluginAssemblies())
|
||||
foreach (var assembly in pluginAssemblies())
|
||||
{
|
||||
if (assembly.FullName.Contains("Views"))
|
||||
{
|
||||
_.ApplicationParts.Add(new CompiledRazorAssemblyPart(assembly));
|
||||
_partManager.ApplicationParts.Add(new CompiledRazorAssemblyPart(assembly));
|
||||
}
|
||||
|
||||
else if (assembly.FullName.Contains("Web"))
|
||||
{
|
||||
_.ApplicationParts.Add(new AssemblyPart(assembly));
|
||||
_partManager.ApplicationParts.Add(new AssemblyPart(assembly));
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -58,7 +76,7 @@ namespace WebfrontCore
|
||||
});
|
||||
#endif
|
||||
|
||||
foreach (var asm in Program.Manager.GetPluginAssemblies())
|
||||
foreach (var asm in pluginAssemblies())
|
||||
{
|
||||
mvcBuilder.AddApplicationPart(asm);
|
||||
}
|
||||
@ -83,7 +101,7 @@ namespace WebfrontCore
|
||||
#endif
|
||||
|
||||
services.AddSingleton(Program.Manager);
|
||||
services.AddSingleton(Program.ApplicationServiceProvider.GetService(typeof(IPluginImporter)) as IPluginImporter);
|
||||
services.AddSingleton(Program.ApplicationServiceProvider.GetService<IConfigurationHandlerFactory>());
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
Loading…
Reference in New Issue
Block a user