Compare commits
4 Commits
release/pr
...
2.3-Prerel
Author | SHA1 | Date | |
---|---|---|---|
|
9117440566 | ||
|
ad6b6a6465 | ||
|
eb8145a168 | ||
|
a560e05df8 |
@ -67,13 +67,14 @@ namespace IW4MAdmin.Application
|
|||||||
private readonly IEventHandler _eventHandler;
|
private readonly IEventHandler _eventHandler;
|
||||||
private readonly IScriptCommandFactory _scriptCommandFactory;
|
private readonly IScriptCommandFactory _scriptCommandFactory;
|
||||||
private readonly IMetaRegistration _metaRegistration;
|
private readonly IMetaRegistration _metaRegistration;
|
||||||
|
private readonly IScriptPluginServiceResolver _scriptPluginServiceResolver;
|
||||||
|
|
||||||
public ApplicationManager(ILogger logger, IMiddlewareActionHandler actionHandler, IEnumerable<IManagerCommand> commands,
|
public ApplicationManager(ILogger logger, IMiddlewareActionHandler actionHandler, IEnumerable<IManagerCommand> commands,
|
||||||
ITranslationLookup translationLookup, IConfigurationHandler<CommandConfiguration> commandConfiguration,
|
ITranslationLookup translationLookup, IConfigurationHandler<CommandConfiguration> commandConfiguration,
|
||||||
IConfigurationHandler<ApplicationConfiguration> appConfigHandler, IGameServerInstanceFactory serverInstanceFactory,
|
IConfigurationHandler<ApplicationConfiguration> appConfigHandler, IGameServerInstanceFactory serverInstanceFactory,
|
||||||
IEnumerable<IPlugin> plugins, IParserRegexFactory parserRegexFactory, IEnumerable<IRegisterEvent> customParserEvents,
|
IEnumerable<IPlugin> plugins, IParserRegexFactory parserRegexFactory, IEnumerable<IRegisterEvent> customParserEvents,
|
||||||
IEventHandler eventHandler, IScriptCommandFactory scriptCommandFactory, IDatabaseContextFactory contextFactory, IMetaService metaService,
|
IEventHandler eventHandler, IScriptCommandFactory scriptCommandFactory, IDatabaseContextFactory contextFactory, IMetaService metaService,
|
||||||
IMetaRegistration metaRegistration)
|
IMetaRegistration metaRegistration, IScriptPluginServiceResolver scriptPluginServiceResolver)
|
||||||
{
|
{
|
||||||
MiddlewareActionHandler = actionHandler;
|
MiddlewareActionHandler = actionHandler;
|
||||||
_servers = new ConcurrentBag<Server>();
|
_servers = new ConcurrentBag<Server>();
|
||||||
@ -100,6 +101,7 @@ namespace IW4MAdmin.Application
|
|||||||
_eventHandler = eventHandler;
|
_eventHandler = eventHandler;
|
||||||
_scriptCommandFactory = scriptCommandFactory;
|
_scriptCommandFactory = scriptCommandFactory;
|
||||||
_metaRegistration = metaRegistration;
|
_metaRegistration = metaRegistration;
|
||||||
|
_scriptPluginServiceResolver = scriptPluginServiceResolver;
|
||||||
Plugins = plugins;
|
Plugins = plugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,12 +279,12 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
if (plugin is ScriptPlugin scriptPlugin)
|
if (plugin is ScriptPlugin scriptPlugin)
|
||||||
{
|
{
|
||||||
await scriptPlugin.Initialize(this, _scriptCommandFactory);
|
await scriptPlugin.Initialize(this, _scriptCommandFactory, _scriptPluginServiceResolver);
|
||||||
scriptPlugin.Watcher.Changed += async (sender, e) =>
|
scriptPlugin.Watcher.Changed += async (sender, e) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await scriptPlugin.Initialize(this, _scriptCommandFactory);
|
await scriptPlugin.Initialize(this, _scriptCommandFactory, _scriptPluginServiceResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -449,7 +451,8 @@ namespace IW4MAdmin.Application
|
|||||||
Name = cmd.Name,
|
Name = cmd.Name,
|
||||||
Alias = cmd.Alias,
|
Alias = cmd.Alias,
|
||||||
MinimumPermission = cmd.Permission,
|
MinimumPermission = cmd.Permission,
|
||||||
AllowImpersonation = cmd.AllowImpersonation
|
AllowImpersonation = cmd.AllowImpersonation,
|
||||||
|
SupportedGames = cmd.SupportedGames
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,6 +255,7 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
ClientNumber = Convert.ToInt32(match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()),
|
ClientNumber = Convert.ToInt32(match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()),
|
||||||
State = EFClient.ClientState.Connecting,
|
State = EFClient.ClientState.Connecting,
|
||||||
},
|
},
|
||||||
|
Extra = originIdString,
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
||||||
IsBlocking = true,
|
IsBlocking = true,
|
||||||
GameTime = gameTime,
|
GameTime = gameTime,
|
||||||
|
@ -816,6 +816,7 @@ namespace IW4MAdmin
|
|||||||
Origin = client,
|
Origin = client,
|
||||||
Owner = this,
|
Owner = this,
|
||||||
IsBlocking = true,
|
IsBlocking = true,
|
||||||
|
Extra = client.GetAdditionalProperty<string>("BotGuid"),
|
||||||
Source = GameEvent.EventSource.Status
|
Source = GameEvent.EventSource.Status
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -249,6 +249,7 @@ namespace IW4MAdmin.Application
|
|||||||
.AddSingleton<IEntityService<EFClient>, ClientService>()
|
.AddSingleton<IEntityService<EFClient>, ClientService>()
|
||||||
.AddSingleton<IMetaService, MetaService>()
|
.AddSingleton<IMetaService, MetaService>()
|
||||||
.AddSingleton<IMetaRegistration, MetaRegistration>()
|
.AddSingleton<IMetaRegistration, MetaRegistration>()
|
||||||
|
.AddSingleton<IScriptPluginServiceResolver, ScriptPluginServiceResolver>()
|
||||||
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, ReceivedPenaltyResponse>, ReceivedPenaltyResourceQueryHelper>()
|
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, ReceivedPenaltyResponse>, ReceivedPenaltyResourceQueryHelper>()
|
||||||
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, AdministeredPenaltyResponse>, AdministeredPenaltyResourceQueryHelper>()
|
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, AdministeredPenaltyResponse>, AdministeredPenaltyResourceQueryHelper>()
|
||||||
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, UpdatedAliasResponse>, UpdatedAliasResourceQueryHelper>()
|
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, UpdatedAliasResponse>, UpdatedAliasResourceQueryHelper>()
|
||||||
|
@ -61,7 +61,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
_onProcessing.Dispose();
|
_onProcessing.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Initialize(IManager manager, IScriptCommandFactory scriptCommandFactory)
|
public async Task Initialize(IManager manager, IScriptCommandFactory scriptCommandFactory, IScriptPluginServiceResolver serviceResolver)
|
||||||
{
|
{
|
||||||
await _onProcessing.WaitAsync();
|
await _onProcessing.WaitAsync();
|
||||||
|
|
||||||
@ -114,6 +114,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
_scriptEngine.Execute(script);
|
_scriptEngine.Execute(script);
|
||||||
_scriptEngine.SetValue("_localization", Utilities.CurrentLocalization);
|
_scriptEngine.SetValue("_localization", Utilities.CurrentLocalization);
|
||||||
|
_scriptEngine.SetValue("_serviceResolver", serviceResolver);
|
||||||
dynamic pluginObject = _scriptEngine.GetValue("plugin").ToObject();
|
dynamic pluginObject = _scriptEngine.GetValue("plugin").ToObject();
|
||||||
|
|
||||||
Author = pluginObject.author;
|
Author = pluginObject.author;
|
||||||
@ -164,6 +165,11 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
successfullyLoaded = true;
|
successfullyLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
catch (JavaScriptException ex)
|
||||||
|
{
|
||||||
|
throw new PluginException($"An error occured while initializing script plugin: {ex.Error} (Line: {ex.Location.Start.Line}, Character: {ex.Location.Start.Column})") { PluginFile = _fileName };
|
||||||
|
}
|
||||||
|
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
throw;
|
throw;
|
||||||
|
31
Application/Misc/ScriptPluginServiceResolver.cs
Normal file
31
Application/Misc/ScriptPluginServiceResolver.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.Misc
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// implementation of IScriptPluginServiceResolver
|
||||||
|
/// </summary>
|
||||||
|
public class ScriptPluginServiceResolver : IScriptPluginServiceResolver
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
public ScriptPluginServiceResolver(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ResolveService(string serviceName)
|
||||||
|
{
|
||||||
|
var serviceType = typeof(IScriptPluginServiceResolver).Assembly.GetTypes().FirstOrDefault(_type => _type.Name == serviceName);
|
||||||
|
|
||||||
|
if (serviceType == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"No service type '{serviceName}' defined in IW4MAdmin assembly");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _serviceProvider.GetService(serviceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -203,10 +203,11 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
|
|
||||||
long networkId;
|
long networkId;
|
||||||
string name = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConName]].TrimNewLine();
|
string name = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConName]].TrimNewLine();
|
||||||
|
string networkIdString;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string networkIdString = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConNetworkId]];
|
networkIdString = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConNetworkId]];
|
||||||
|
|
||||||
networkId = networkIdString.IsBotGuid() ?
|
networkId = networkIdString.IsBotGuid() ?
|
||||||
name.GenerateGuidFromString() :
|
name.GenerateGuidFromString() :
|
||||||
@ -234,6 +235,8 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
State = EFClient.ClientState.Connecting
|
State = EFClient.ClientState.Connecting
|
||||||
};
|
};
|
||||||
|
|
||||||
|
client.SetAdditionalProperty("BotGuid", networkIdString);
|
||||||
|
|
||||||
StatusPlayers.Add(client);
|
StatusPlayers.Add(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||||||
GameFiles\IW4x\userraw\scripts\_commands.gsc = GameFiles\IW4x\userraw\scripts\_commands.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
|
GameFiles\IW4x\userraw\scripts\_customcallbacks.gsc = GameFiles\IW4x\userraw\scripts\_customcallbacks.gsc
|
||||||
PostPublish.ps1 = PostPublish.ps1
|
PostPublish.ps1 = PostPublish.ps1
|
||||||
|
pre-release-pipeline.yml = pre-release-pipeline.yml
|
||||||
README.md = README.md
|
README.md = README.md
|
||||||
RunPublishPre.cmd = RunPublishPre.cmd
|
RunPublishPre.cmd = RunPublishPre.cmd
|
||||||
RunPublishRelease.cmd = RunPublishRelease.cmd
|
RunPublishRelease.cmd = RunPublishRelease.cmd
|
||||||
|
@ -74,14 +74,14 @@ namespace LiveRadar.Web.Controllers
|
|||||||
[Route("Radar/Update")]
|
[Route("Radar/Update")]
|
||||||
public IActionResult Update(string payload)
|
public IActionResult Update(string payload)
|
||||||
{
|
{
|
||||||
var radarUpdate = RadarEvent.Parse(payload);
|
/*var radarUpdate = RadarEvent.Parse(payload);
|
||||||
var client = _manager.GetActiveClients().FirstOrDefault(_client => _client.NetworkId == radarUpdate.Guid);
|
var client = _manager.GetActiveClients().FirstOrDefault(_client => _client.NetworkId == radarUpdate.Guid);
|
||||||
|
|
||||||
if (client != null)
|
if (client != null)
|
||||||
{
|
{
|
||||||
radarUpdate.Name = client.Name.StripColors();
|
radarUpdate.Name = client.Name.StripColors();
|
||||||
client.SetAdditionalProperty("LiveRadar", radarUpdate);
|
client.SetAdditionalProperty("LiveRadar", radarUpdate);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
33
Plugins/LiveRadar/Events/Script.cs
Normal file
33
Plugins/LiveRadar/Events/Script.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Database.Models;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using EventGeneratorCallback = System.ValueTuple<string, string,
|
||||||
|
System.Func<string, SharedLibraryCore.Interfaces.IEventParserConfiguration,
|
||||||
|
SharedLibraryCore.GameEvent,
|
||||||
|
SharedLibraryCore.GameEvent>>;
|
||||||
|
|
||||||
|
namespace LiveRadar.Events
|
||||||
|
{
|
||||||
|
public class Script : IRegisterEvent
|
||||||
|
{
|
||||||
|
private const string EVENT_LIVERADAR = "LiveRadar";
|
||||||
|
private EventGeneratorCallback LiveRadar()
|
||||||
|
{
|
||||||
|
return (EVENT_LIVERADAR, EVENT_LIVERADAR, (string eventLine, IEventParserConfiguration config, GameEvent autoEvent) =>
|
||||||
|
{
|
||||||
|
string[] lineSplit = eventLine.Split(";");
|
||||||
|
|
||||||
|
autoEvent.Type = GameEvent.EventType.Other;
|
||||||
|
autoEvent.Subtype = EVENT_LIVERADAR;
|
||||||
|
autoEvent.Origin = new EFClient() { NetworkId = 0 };
|
||||||
|
autoEvent.Extra = lineSplit[1]; // guid
|
||||||
|
|
||||||
|
return autoEvent;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<EventGeneratorCallback> Events => new[] { LiveRadar() };
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ using SharedLibraryCore;
|
|||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -17,12 +18,14 @@ namespace LiveRadar
|
|||||||
public string Author => "RaidMax";
|
public string Author => "RaidMax";
|
||||||
|
|
||||||
private readonly IConfigurationHandler<LiveRadarConfiguration> _configurationHandler;
|
private readonly IConfigurationHandler<LiveRadarConfiguration> _configurationHandler;
|
||||||
|
private readonly Dictionary<string, long> _botGuidLookups;
|
||||||
private bool addedPage;
|
private bool addedPage;
|
||||||
private readonly object lockObject = new object();
|
private readonly object lockObject = new object();
|
||||||
|
|
||||||
public Plugin(IConfigurationHandlerFactory configurationHandlerFactory)
|
public Plugin(IConfigurationHandlerFactory configurationHandlerFactory)
|
||||||
{
|
{
|
||||||
_configurationHandler = configurationHandlerFactory.GetConfigurationHandler<LiveRadarConfiguration>("LiveRadarConfiguration");
|
_configurationHandler = configurationHandlerFactory.GetConfigurationHandler<LiveRadarConfiguration>("LiveRadarConfiguration");
|
||||||
|
_botGuidLookups = new Dictionary<string, long>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task OnEventAsync(GameEvent E, Server S)
|
public Task OnEventAsync(GameEvent E, Server S)
|
||||||
@ -41,28 +44,45 @@ namespace LiveRadar
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (E.Type == GameEvent.EventType.Unknown)
|
if (E.Type == GameEvent.EventType.PreConnect && E.Origin.IsBot)
|
||||||
{
|
{
|
||||||
if (E.Data?.StartsWith("LiveRadar") ?? false)
|
string botKey = $"BotGuid_{E.Extra}";
|
||||||
|
lock (lockObject)
|
||||||
{
|
{
|
||||||
try
|
if (!_botGuidLookups.ContainsKey(botKey))
|
||||||
{
|
{
|
||||||
var radarUpdate = RadarEvent.Parse(E.Data);
|
_botGuidLookups.Add(botKey, E.Origin.NetworkId);
|
||||||
var client = S.Manager.GetActiveClients().FirstOrDefault(_client => _client.NetworkId == radarUpdate.Guid);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (client != null)
|
if (E.Type == GameEvent.EventType.Other && E.Subtype == "LiveRadar")
|
||||||
{
|
{
|
||||||
radarUpdate.Name = client.Name.StripColors();
|
try
|
||||||
client.SetAdditionalProperty("LiveRadar", radarUpdate);
|
{
|
||||||
}
|
string botKey = $"BotGuid_{E.Extra}";
|
||||||
|
long generatedBotGuid;
|
||||||
|
|
||||||
|
lock (lockObject)
|
||||||
|
{
|
||||||
|
generatedBotGuid = _botGuidLookups.ContainsKey(botKey) ? _botGuidLookups[botKey] : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e)
|
var radarUpdate = RadarEvent.Parse(E.Data, generatedBotGuid);
|
||||||
|
var client = S.Manager.GetActiveClients().FirstOrDefault(_client => _client.NetworkId == radarUpdate.Guid);
|
||||||
|
|
||||||
|
if (client != null)
|
||||||
{
|
{
|
||||||
S.Logger.WriteWarning($"Could not parse live radar output: {e.Data}");
|
radarUpdate.Name = client.Name.StripColors();
|
||||||
S.Logger.WriteDebug(e.GetExceptionInfo());
|
client.SetAdditionalProperty("LiveRadar", radarUpdate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
S.Logger.WriteWarning($"Could not parse live radar output: {e.Data}");
|
||||||
|
S.Logger.WriteDebug(e.GetExceptionInfo());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Helpers;
|
using SharedLibraryCore.Helpers;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace LiveRadar
|
namespace LiveRadar
|
||||||
{
|
{
|
||||||
@ -39,13 +37,13 @@ namespace LiveRadar
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RadarEvent Parse(string input)
|
public static RadarEvent Parse(string input, long generatedBotGuid)
|
||||||
{
|
{
|
||||||
var items = input.Split(';').Skip(1).ToList();
|
var items = input.Split(';').Skip(1).ToList();
|
||||||
|
|
||||||
var parsedEvent = new RadarEvent()
|
var parsedEvent = new RadarEvent()
|
||||||
{
|
{
|
||||||
Guid = items[0].ConvertGuidToLong(System.Globalization.NumberStyles.HexNumber),
|
Guid = generatedBotGuid,
|
||||||
Location = Vector3.Parse(items[1]),
|
Location = Vector3.Parse(items[1]),
|
||||||
ViewAngles = Vector3.Parse(items[2]).FixIW4Angles(),
|
ViewAngles = Vector3.Parse(items[2]).FixIW4Angles(),
|
||||||
Team = items[3],
|
Team = items[3],
|
||||||
|
@ -44,6 +44,8 @@ let plugin = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
onLoadAsync: function (manager) {
|
onLoadAsync: function (manager) {
|
||||||
|
this.logger = _serviceResolver.ResolveService("ILogger");
|
||||||
|
this.logger.WriteDebug("sample plugin loaded");
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnloadAsync: function () {
|
onUnloadAsync: function () {
|
||||||
|
@ -1232,6 +1232,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
return 886229536;
|
return 886229536;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: this is not stable and will need to be migrated again...
|
||||||
long id = HashCode.Combine(server.IP, server.Port);
|
long id = HashCode.Combine(server.IP, server.Port);
|
||||||
id = id < 0 ? Math.Abs(id) : id;
|
id = id < 0 ? Math.Abs(id) : id;
|
||||||
long? serverId;
|
long? serverId;
|
||||||
|
@ -5,6 +5,7 @@ using SharedLibraryCore.Commands;
|
|||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using static SharedLibraryCore.Server;
|
||||||
|
|
||||||
namespace SharedLibraryCore
|
namespace SharedLibraryCore
|
||||||
{
|
{
|
||||||
@ -13,7 +14,7 @@ namespace SharedLibraryCore
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class Command : IManagerCommand
|
public abstract class Command : IManagerCommand
|
||||||
{
|
{
|
||||||
private readonly CommandConfiguration _config;
|
protected readonly CommandConfiguration _config;
|
||||||
protected readonly ITranslationLookup _translationLookup;
|
protected readonly ITranslationLookup _translationLookup;
|
||||||
protected ILogger logger;
|
protected ILogger logger;
|
||||||
|
|
||||||
@ -113,6 +114,25 @@ namespace SharedLibraryCore
|
|||||||
}
|
}
|
||||||
private EFClient.Permission permission;
|
private EFClient.Permission permission;
|
||||||
|
|
||||||
|
public Game[] SupportedGames
|
||||||
|
{
|
||||||
|
get => supportedGames;
|
||||||
|
protected set
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var savedGames = _config?.Commands[GetType().Name].SupportedGames;
|
||||||
|
supportedGames = savedGames?.Length != 0 ? savedGames : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (KeyNotFoundException)
|
||||||
|
{
|
||||||
|
supportedGames = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private Game[] supportedGames;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Argument list for the command
|
/// Argument list for the command
|
||||||
|
37
SharedLibraryCore/Commands/PrivateMessageAdminsCommand.cs
Normal file
37
SharedLibraryCore/Commands/PrivateMessageAdminsCommand.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using SharedLibraryCore.Configuration;
|
||||||
|
using SharedLibraryCore.Database.Models;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static SharedLibraryCore.Server;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Commands
|
||||||
|
{
|
||||||
|
public class PrivateMessageAdminsCommand : Command
|
||||||
|
{
|
||||||
|
public PrivateMessageAdminsCommand(CommandConfiguration config, ITranslationLookup lookup) : base(config, lookup)
|
||||||
|
{
|
||||||
|
Name = "privatemessageadmin";
|
||||||
|
Description = lookup["COMMANDS_PMADMINS_DESC"];
|
||||||
|
Alias = "pma";
|
||||||
|
Permission = EFClient.Permission.Moderator;
|
||||||
|
SupportedGames = new[] { Game.IW4, Game.IW5 };
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task ExecuteAsync(GameEvent E)
|
||||||
|
{
|
||||||
|
bool isGameSupported = _config.Commands[nameof(PrivateMessageAdminsCommand)].SupportedGames.Length > 0 &&
|
||||||
|
_config.Commands[nameof(PrivateMessageAdminsCommand)].SupportedGames.Contains(E.Owner.GameName);
|
||||||
|
|
||||||
|
if (!isGameSupported)
|
||||||
|
{
|
||||||
|
E.Origin.Tell(_translationLookup["COMMANDS_GAME_NOT_SUPPORTED"].FormatExt(nameof(PrivateMessageAdminsCommand)));
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
E.Owner.ToAdmins(E.Data);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json;
|
||||||
using System.Text.Json.Serialization;
|
using Newtonsoft.Json.Converters;
|
||||||
using static SharedLibraryCore.Database.Models.EFClient;
|
using static SharedLibraryCore.Database.Models.EFClient;
|
||||||
|
using static SharedLibraryCore.Server;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Configuration
|
namespace SharedLibraryCore.Configuration
|
||||||
{
|
{
|
||||||
@ -29,5 +30,11 @@ namespace SharedLibraryCore.Configuration
|
|||||||
/// Indicates if the command can be run by another user (impersonation)
|
/// Indicates if the command can be run by another user (impersonation)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowImpersonation { get; set; }
|
public bool AllowImpersonation { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the games supporting the functionality of the command
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
|
||||||
|
public Game[] SupportedGames { get; set; } = new Game[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using System;
|
namespace SharedLibraryCore.Dtos.Meta.Responses
|
||||||
|
|
||||||
namespace SharedLibraryCore.Dtos.Meta.Responses
|
|
||||||
{
|
{
|
||||||
public class UpdatedAliasResponse : BaseMetaResponse
|
public class UpdatedAliasResponse : BaseMetaResponse
|
||||||
{
|
{
|
||||||
@ -17,6 +15,6 @@ namespace SharedLibraryCore.Dtos.Meta.Responses
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode() => HashCode.Combine(Name.StripColors(), IPAddress);
|
public override int GetHashCode() => $"{Name.StripColors()}{IPAddress}".GetStableHashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using static SharedLibraryCore.Database.Models.EFClient;
|
using static SharedLibraryCore.Database.Models.EFClient;
|
||||||
|
using static SharedLibraryCore.Server;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Interfaces
|
namespace SharedLibraryCore.Interfaces
|
||||||
{
|
{
|
||||||
@ -35,6 +36,11 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Permission Permission { get; }
|
Permission Permission { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Games the command is supported on
|
||||||
|
/// </summary>
|
||||||
|
Game[] SupportedGames { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Syntax for using the command
|
/// Syntax for using the command
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
10
SharedLibraryCore/Interfaces/IScriptPluginServiceResolver.cs
Normal file
10
SharedLibraryCore/Interfaces/IScriptPluginServiceResolver.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace SharedLibraryCore.Interfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// interface used to dynamically resolve services by string name
|
||||||
|
/// </summary>
|
||||||
|
public interface IScriptPluginServiceResolver
|
||||||
|
{
|
||||||
|
object ResolveService(string serviceName);
|
||||||
|
}
|
||||||
|
}
|
@ -369,7 +369,27 @@ namespace SharedLibraryCore
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">value string</param>
|
/// <param name="value">value string</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static long GenerateGuidFromString(this string value) => string.IsNullOrEmpty(value) ? -1 : HashCode.Combine(value.StripColors());
|
public static long GenerateGuidFromString(this string value) => string.IsNullOrEmpty(value) ? -1 : GetStableHashCode(value.StripColors());
|
||||||
|
|
||||||
|
/// https://stackoverflow.com/questions/36845430/persistent-hashcode-for-strings
|
||||||
|
public static int GetStableHashCode(this string str)
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
int hash1 = 5381;
|
||||||
|
int hash2 = hash1;
|
||||||
|
|
||||||
|
for (int i = 0; i < str.Length && str[i] != '\0'; i += 2)
|
||||||
|
{
|
||||||
|
hash1 = ((hash1 << 5) + hash1) ^ str[i];
|
||||||
|
if (i == str.Length - 1 || str[i + 1] == '\0')
|
||||||
|
break;
|
||||||
|
hash2 = ((hash2 << 5) + hash2) ^ str[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash1 + (hash2 * 1566083941);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static int? ConvertToIP(this string str)
|
public static int? ConvertToIP(this string str)
|
||||||
{
|
{
|
||||||
@ -773,6 +793,8 @@ namespace SharedLibraryCore
|
|||||||
byte[] bytes = toTest.GetAddressBytes();
|
byte[] bytes = toTest.GetAddressBytes();
|
||||||
switch (bytes[0])
|
switch (bytes[0])
|
||||||
{
|
{
|
||||||
|
case 0:
|
||||||
|
return bytes[1] == 0 && bytes[2] == 0 && bytes[3] == 0;
|
||||||
case 10:
|
case 10:
|
||||||
return true;
|
return true;
|
||||||
case 172:
|
case 172:
|
||||||
@ -954,7 +976,7 @@ namespace SharedLibraryCore
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// wrapper method for humanizee that uses current current culture
|
/// wrapper method for humanizee that uses current current culture
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string HumanizeForCurrentCulture(this TimeSpan timeSpan, int precision = 1, TimeUnit maxUnit = TimeUnit.Week,
|
public static string HumanizeForCurrentCulture(this TimeSpan timeSpan, int precision = 1, TimeUnit maxUnit = TimeUnit.Week,
|
||||||
TimeUnit minUnit = TimeUnit.Millisecond, string collectionSeparator = ", ", bool toWords = false)
|
TimeUnit minUnit = TimeUnit.Millisecond, string collectionSeparator = ", ", bool toWords = false)
|
||||||
{
|
{
|
||||||
return timeSpan.Humanize(precision, CurrentLocalization.Culture, maxUnit, minUnit, collectionSeparator, toWords);
|
return timeSpan.Humanize(precision, CurrentLocalization.Culture, maxUnit, minUnit, collectionSeparator, toWords);
|
||||||
|
@ -537,5 +537,46 @@ namespace ApplicationTests
|
|||||||
Assert.IsTrue(result.IsBroadcast);
|
Assert.IsTrue(result.IsBroadcast);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region PMADMINS
|
||||||
|
[Test]
|
||||||
|
public async Task Test_PrivateMessageAdmins_HappyPath()
|
||||||
|
{
|
||||||
|
var cmd = new PrivateMessageAdminsCommand(cmdConfig, transLookup);
|
||||||
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
|
var origin = ClientGenerators.CreateDatabaseClient();
|
||||||
|
origin.Level = Permission.Administrator;
|
||||||
|
origin.CurrentServer = server;
|
||||||
|
var gameEvent = EventGenerators.GenerateEvent(GameEvent.EventType.Command, "", server);
|
||||||
|
cmdConfig.Commands.Add(nameof(PrivateMessageAdminsCommand), new CommandProperties { SupportedGames = new[] { server.GameName } });
|
||||||
|
|
||||||
|
server.Clients[0] = origin;
|
||||||
|
server.Clients[1] = origin;
|
||||||
|
await cmd.ExecuteAsync(gameEvent);
|
||||||
|
int expectedEvents = 2;
|
||||||
|
|
||||||
|
Assert.AreEqual(expectedEvents, mockEventHandler.Events.Count(_event => _event.Type == GameEvent.EventType.Tell));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Test_PrivateMessageAdmins_GameNotSupported()
|
||||||
|
{
|
||||||
|
var cmd = new PrivateMessageAdminsCommand(cmdConfig, transLookup);
|
||||||
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
|
var origin = ClientGenerators.CreateDatabaseClient();
|
||||||
|
origin.Level = Permission.Administrator;
|
||||||
|
origin.CurrentServer = server;
|
||||||
|
var gameEvent = EventGenerators.GenerateEvent(GameEvent.EventType.Command, "", server);
|
||||||
|
gameEvent.Origin = origin;
|
||||||
|
cmdConfig.Commands.Add(nameof(PrivateMessageAdminsCommand), new CommandProperties());
|
||||||
|
|
||||||
|
server.Clients[0] = origin;
|
||||||
|
server.Clients[1] = origin;
|
||||||
|
await cmd.ExecuteAsync(gameEvent);
|
||||||
|
int expectedEvents = 1;
|
||||||
|
|
||||||
|
Assert.AreEqual(expectedEvents, mockEventHandler.Events.Count(_event => _event.Type == GameEvent.EventType.Tell));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,7 @@ trigger:
|
|||||||
batch: true
|
batch: true
|
||||||
branches:
|
branches:
|
||||||
include:
|
include:
|
||||||
- releases/*
|
- release/pre
|
||||||
- 2.4-pr
|
|
||||||
paths:
|
|
||||||
exclude:
|
|
||||||
- azure-pipelines.yml
|
|
||||||
- Master/*
|
|
||||||
|
|
||||||
pr: none
|
pr: none
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user