Compare commits
4 Commits
2.3-Prerel
...
2.3-Prerel
Author | SHA1 | Date | |
---|---|---|---|
f704708264 | |||
d9d3c75106 | |||
9d11cd5088 | |||
9e1a178667 |
@ -67,14 +67,13 @@ namespace IW4MAdmin.Application
|
||||
private readonly IEventHandler _eventHandler;
|
||||
private readonly IScriptCommandFactory _scriptCommandFactory;
|
||||
private readonly IMetaRegistration _metaRegistration;
|
||||
private readonly IScriptPluginServiceResolver _scriptPluginServiceResolver;
|
||||
|
||||
public ApplicationManager(ILogger logger, IMiddlewareActionHandler actionHandler, IEnumerable<IManagerCommand> commands,
|
||||
ITranslationLookup translationLookup, IConfigurationHandler<CommandConfiguration> commandConfiguration,
|
||||
IConfigurationHandler<ApplicationConfiguration> appConfigHandler, IGameServerInstanceFactory serverInstanceFactory,
|
||||
IEnumerable<IPlugin> plugins, IParserRegexFactory parserRegexFactory, IEnumerable<IRegisterEvent> customParserEvents,
|
||||
IEventHandler eventHandler, IScriptCommandFactory scriptCommandFactory, IDatabaseContextFactory contextFactory, IMetaService metaService,
|
||||
IMetaRegistration metaRegistration, IScriptPluginServiceResolver scriptPluginServiceResolver)
|
||||
IMetaRegistration metaRegistration)
|
||||
{
|
||||
MiddlewareActionHandler = actionHandler;
|
||||
_servers = new ConcurrentBag<Server>();
|
||||
@ -101,7 +100,6 @@ namespace IW4MAdmin.Application
|
||||
_eventHandler = eventHandler;
|
||||
_scriptCommandFactory = scriptCommandFactory;
|
||||
_metaRegistration = metaRegistration;
|
||||
_scriptPluginServiceResolver = scriptPluginServiceResolver;
|
||||
Plugins = plugins;
|
||||
}
|
||||
|
||||
@ -279,12 +277,12 @@ namespace IW4MAdmin.Application
|
||||
{
|
||||
if (plugin is ScriptPlugin scriptPlugin)
|
||||
{
|
||||
await scriptPlugin.Initialize(this, _scriptCommandFactory, _scriptPluginServiceResolver);
|
||||
await scriptPlugin.Initialize(this, _scriptCommandFactory);
|
||||
scriptPlugin.Watcher.Changed += async (sender, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await scriptPlugin.Initialize(this, _scriptCommandFactory, _scriptPluginServiceResolver);
|
||||
await scriptPlugin.Initialize(this, _scriptCommandFactory);
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
@ -451,8 +449,7 @@ namespace IW4MAdmin.Application
|
||||
Name = cmd.Name,
|
||||
Alias = cmd.Alias,
|
||||
MinimumPermission = cmd.Permission,
|
||||
AllowImpersonation = cmd.AllowImpersonation,
|
||||
SupportedGames = cmd.SupportedGames
|
||||
AllowImpersonation = cmd.AllowImpersonation
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -255,7 +255,6 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
ClientNumber = Convert.ToInt32(match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()),
|
||||
State = EFClient.ClientState.Connecting,
|
||||
},
|
||||
Extra = originIdString,
|
||||
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
||||
IsBlocking = true,
|
||||
GameTime = gameTime,
|
||||
|
@ -25,7 +25,7 @@ namespace IW4MAdmin.Application.Factories
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IManagerCommand CreateScriptCommand(string name, string alias, string description, string permission, bool isTargetRequired, IEnumerable<(string, bool)> args, Action<GameEvent> executeAction)
|
||||
public IManagerCommand CreateScriptCommand(string name, string alias, string description, string permission, IEnumerable<(string, bool)> args, Action<GameEvent> executeAction)
|
||||
{
|
||||
var permissionEnum = Enum.Parse<Permission>(permission);
|
||||
var argsArray = args.Select(_arg => new CommandArgument
|
||||
@ -34,7 +34,7 @@ namespace IW4MAdmin.Application.Factories
|
||||
Required = _arg.Item2
|
||||
}).ToArray();
|
||||
|
||||
return new ScriptCommand(name, alias, description, isTargetRequired, permissionEnum, argsArray, executeAction, _config, _transLookup);
|
||||
return new ScriptCommand(name, alias, description, permissionEnum, argsArray, executeAction, _config, _transLookup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -785,7 +785,7 @@ namespace IW4MAdmin
|
||||
|
||||
var polledClients = await PollPlayersAsync();
|
||||
|
||||
foreach (var disconnectingClient in polledClients[1].Where(_client => !_client.IsZombieClient /* ignores "fake" zombie clients */))
|
||||
foreach (var disconnectingClient in polledClients[1])
|
||||
{
|
||||
disconnectingClient.CurrentServer = this;
|
||||
var e = new GameEvent()
|
||||
@ -816,7 +816,6 @@ namespace IW4MAdmin
|
||||
Origin = client,
|
||||
Owner = this,
|
||||
IsBlocking = true,
|
||||
Extra = client.GetAdditionalProperty<string>("BotGuid"),
|
||||
Source = GameEvent.EventSource.Status
|
||||
};
|
||||
|
||||
|
@ -249,7 +249,6 @@ namespace IW4MAdmin.Application
|
||||
.AddSingleton<IEntityService<EFClient>, ClientService>()
|
||||
.AddSingleton<IMetaService, MetaService>()
|
||||
.AddSingleton<IMetaRegistration, MetaRegistration>()
|
||||
.AddSingleton<IScriptPluginServiceResolver, ScriptPluginServiceResolver>()
|
||||
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, ReceivedPenaltyResponse>, ReceivedPenaltyResourceQueryHelper>()
|
||||
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, AdministeredPenaltyResponse>, AdministeredPenaltyResourceQueryHelper>()
|
||||
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, UpdatedAliasResponse>, UpdatedAliasResourceQueryHelper>()
|
||||
|
@ -15,7 +15,7 @@ namespace IW4MAdmin.Application.Misc
|
||||
{
|
||||
private readonly Action<GameEvent> _executeAction;
|
||||
|
||||
public ScriptCommand(string name, string alias, string description, bool isTargetRequired, Permission permission,
|
||||
public ScriptCommand(string name, string alias, string description, Permission permission,
|
||||
CommandArgument[] args, Action<GameEvent> executeAction, CommandConfiguration config, ITranslationLookup layout)
|
||||
: base(config, layout)
|
||||
{
|
||||
@ -24,7 +24,6 @@ namespace IW4MAdmin.Application.Misc
|
||||
Name = name;
|
||||
Alias = alias;
|
||||
Description = description;
|
||||
RequiresTarget = isTargetRequired;
|
||||
Permission = permission;
|
||||
Arguments = args;
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ namespace IW4MAdmin.Application.Misc
|
||||
_onProcessing.Dispose();
|
||||
}
|
||||
|
||||
public async Task Initialize(IManager manager, IScriptCommandFactory scriptCommandFactory, IScriptPluginServiceResolver serviceResolver)
|
||||
public async Task Initialize(IManager manager, IScriptCommandFactory scriptCommandFactory)
|
||||
{
|
||||
await _onProcessing.WaitAsync();
|
||||
|
||||
@ -114,7 +114,6 @@ namespace IW4MAdmin.Application.Misc
|
||||
|
||||
_scriptEngine.Execute(script);
|
||||
_scriptEngine.SetValue("_localization", Utilities.CurrentLocalization);
|
||||
_scriptEngine.SetValue("_serviceResolver", serviceResolver);
|
||||
dynamic pluginObject = _scriptEngine.GetValue("plugin").ToObject();
|
||||
|
||||
Author = pluginObject.author;
|
||||
@ -165,11 +164,6 @@ namespace IW4MAdmin.Application.Misc
|
||||
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
|
||||
{
|
||||
throw;
|
||||
@ -252,7 +246,6 @@ namespace IW4MAdmin.Application.Misc
|
||||
string alias = dynamicCommand.alias;
|
||||
string description = dynamicCommand.description;
|
||||
string permission = dynamicCommand.permission;
|
||||
bool targetRequired = false;
|
||||
|
||||
List<(string, bool)> args = new List<(string, bool)>();
|
||||
dynamic arguments = null;
|
||||
@ -267,16 +260,6 @@ namespace IW4MAdmin.Application.Misc
|
||||
// arguments are optional
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
targetRequired = dynamicCommand.targetRequired;
|
||||
}
|
||||
|
||||
catch (RuntimeBinderException)
|
||||
{
|
||||
// arguments are optional
|
||||
}
|
||||
|
||||
if (arguments != null)
|
||||
{
|
||||
foreach (var arg in dynamicCommand.arguments)
|
||||
@ -301,7 +284,7 @@ namespace IW4MAdmin.Application.Misc
|
||||
}
|
||||
}
|
||||
|
||||
commandList.Add(scriptCommandFactory.CreateScriptCommand(name, alias, description, permission, targetRequired, args, execute));
|
||||
commandList.Add(scriptCommandFactory.CreateScriptCommand(name, alias, description, permission, args, execute));
|
||||
}
|
||||
|
||||
return commandList;
|
||||
|
@ -1,48 +0,0 @@
|
||||
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 = DetermineRootType(serviceName);
|
||||
return _serviceProvider.GetService(serviceType);
|
||||
}
|
||||
|
||||
public object ResolveService(string serviceName, string[] genericParameters)
|
||||
{
|
||||
var serviceType = DetermineRootType(serviceName, genericParameters.Length);
|
||||
var genericTypes = genericParameters.Select(_genericTypeParam => DetermineRootType(_genericTypeParam));
|
||||
var resolvedServiceType = serviceType.MakeGenericType(genericTypes.ToArray());
|
||||
return _serviceProvider.GetService(resolvedServiceType);
|
||||
}
|
||||
|
||||
private Type DetermineRootType(string serviceName, int genericParamCount = 0)
|
||||
{
|
||||
var typeCollection = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(t => t.GetTypes());
|
||||
string generatedName = $"{serviceName}{(genericParamCount == 0 ? "" : $"`{genericParamCount}")}".ToLower();
|
||||
var serviceType = typeCollection.FirstOrDefault(_type => _type.Name.ToLower() == generatedName);
|
||||
|
||||
if (serviceType == null)
|
||||
{
|
||||
throw new InvalidOperationException($"No object type '{serviceName}' defined in loaded assemblies");
|
||||
}
|
||||
|
||||
return serviceType;
|
||||
}
|
||||
}
|
||||
}
|
@ -203,11 +203,10 @@ namespace IW4MAdmin.Application.RconParsers
|
||||
|
||||
long networkId;
|
||||
string name = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConName]].TrimNewLine();
|
||||
string networkIdString;
|
||||
|
||||
try
|
||||
{
|
||||
networkIdString = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConNetworkId]];
|
||||
string networkIdString = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConNetworkId]];
|
||||
|
||||
networkId = networkIdString.IsBotGuid() ?
|
||||
name.GenerateGuidFromString() :
|
||||
@ -235,8 +234,6 @@ namespace IW4MAdmin.Application.RconParsers
|
||||
State = EFClient.ClientState.Connecting
|
||||
};
|
||||
|
||||
client.SetAdditionalProperty("BotGuid", networkIdString);
|
||||
|
||||
StatusPlayers.Add(client);
|
||||
}
|
||||
}
|
||||
|
@ -74,14 +74,14 @@ namespace LiveRadar.Web.Controllers
|
||||
[Route("Radar/Update")]
|
||||
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);
|
||||
|
||||
if (client != null)
|
||||
{
|
||||
radarUpdate.Name = client.Name.StripColors();
|
||||
client.SetAdditionalProperty("LiveRadar", radarUpdate);
|
||||
}*/
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
@ -1,33 +0,0 @@
|
||||
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,7 +3,6 @@ using SharedLibraryCore;
|
||||
using SharedLibraryCore.Configuration;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -18,14 +17,12 @@ namespace LiveRadar
|
||||
public string Author => "RaidMax";
|
||||
|
||||
private readonly IConfigurationHandler<LiveRadarConfiguration> _configurationHandler;
|
||||
private readonly Dictionary<string, long> _botGuidLookups;
|
||||
private bool addedPage;
|
||||
private readonly object lockObject = new object();
|
||||
|
||||
public Plugin(IConfigurationHandlerFactory configurationHandlerFactory)
|
||||
{
|
||||
_configurationHandler = configurationHandlerFactory.GetConfigurationHandler<LiveRadarConfiguration>("LiveRadarConfiguration");
|
||||
_botGuidLookups = new Dictionary<string, long>();
|
||||
}
|
||||
|
||||
public Task OnEventAsync(GameEvent E, Server S)
|
||||
@ -44,45 +41,28 @@ namespace LiveRadar
|
||||
}
|
||||
}
|
||||
|
||||
if (E.Type == GameEvent.EventType.PreConnect && E.Origin.IsBot)
|
||||
if (E.Type == GameEvent.EventType.Unknown)
|
||||
{
|
||||
string botKey = $"BotGuid_{E.Extra}";
|
||||
lock (lockObject)
|
||||
if (E.Data?.StartsWith("LiveRadar") ?? false)
|
||||
{
|
||||
if (!_botGuidLookups.ContainsKey(botKey))
|
||||
try
|
||||
{
|
||||
_botGuidLookups.Add(botKey, E.Origin.NetworkId);
|
||||
}
|
||||
}
|
||||
}
|
||||
var radarUpdate = RadarEvent.Parse(E.Data);
|
||||
var client = S.Manager.GetActiveClients().FirstOrDefault(_client => _client.NetworkId == radarUpdate.Guid);
|
||||
|
||||
if (E.Type == GameEvent.EventType.Other && E.Subtype == "LiveRadar")
|
||||
{
|
||||
try
|
||||
{
|
||||
string botKey = $"BotGuid_{E.Extra}";
|
||||
long generatedBotGuid;
|
||||
|
||||
lock (lockObject)
|
||||
{
|
||||
generatedBotGuid = _botGuidLookups.ContainsKey(botKey) ? _botGuidLookups[botKey] : 0;
|
||||
if (client != null)
|
||||
{
|
||||
radarUpdate.Name = client.Name.StripColors();
|
||||
client.SetAdditionalProperty("LiveRadar", radarUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
var radarUpdate = RadarEvent.Parse(E.Data, generatedBotGuid);
|
||||
var client = S.Manager.GetActiveClients().FirstOrDefault(_client => _client.NetworkId == radarUpdate.Guid);
|
||||
|
||||
if (client != null)
|
||||
catch (Exception e)
|
||||
{
|
||||
radarUpdate.Name = client.Name.StripColors();
|
||||
client.SetAdditionalProperty("LiveRadar", radarUpdate);
|
||||
S.Logger.WriteWarning($"Could not parse live radar output: {e.Data}");
|
||||
S.Logger.WriteDebug(e.GetExceptionInfo());
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
S.Logger.WriteWarning($"Could not parse live radar output: {e.Data}");
|
||||
S.Logger.WriteDebug(e.GetExceptionInfo());
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
@ -1,7 +1,9 @@
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace LiveRadar
|
||||
{
|
||||
@ -37,13 +39,13 @@ namespace LiveRadar
|
||||
return false;
|
||||
}
|
||||
|
||||
public static RadarEvent Parse(string input, long generatedBotGuid)
|
||||
public static RadarEvent Parse(string input)
|
||||
{
|
||||
var items = input.Split(';').Skip(1).ToList();
|
||||
|
||||
var parsedEvent = new RadarEvent()
|
||||
{
|
||||
Guid = generatedBotGuid,
|
||||
Guid = items[0].ConvertGuidToLong(System.Globalization.NumberStyles.HexNumber),
|
||||
Location = Vector3.Parse(items[1]),
|
||||
ViewAngles = Vector3.Parse(items[2]).FixIW4Angles(),
|
||||
Team = items[3],
|
||||
|
@ -7,8 +7,6 @@ let commands = [{
|
||||
alias: "pp",
|
||||
// required
|
||||
permission: "User",
|
||||
// optional (defaults to false)
|
||||
targetRequired: false,
|
||||
// optional
|
||||
arguments: [{
|
||||
name: "times to ping",
|
||||
@ -46,8 +44,6 @@ let plugin = {
|
||||
},
|
||||
|
||||
onLoadAsync: function (manager) {
|
||||
this.logger = _serviceResolver.ResolveService("ILogger");
|
||||
this.logger.WriteDebug("sample plugin loaded");
|
||||
},
|
||||
|
||||
onUnloadAsync: function () {
|
||||
|
@ -20,8 +20,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
Offset,
|
||||
Strain,
|
||||
Recoil,
|
||||
Snap,
|
||||
Button
|
||||
Snap
|
||||
};
|
||||
|
||||
public ChangeTracking<EFACSnapshot> Tracker { get; private set; }
|
||||
@ -39,12 +38,11 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
ILogger Log;
|
||||
Strain Strain;
|
||||
readonly DateTime ConnectionTime = DateTime.UtcNow;
|
||||
private double mapAverageRecoilAmount;
|
||||
private double sessionAverageRecoilAmount;
|
||||
private double sessionAverageSnapAmount;
|
||||
private int sessionSnapHits;
|
||||
private EFClientKill lastHit;
|
||||
private int validRecoilHitCount;
|
||||
private int validButtonHitCount;
|
||||
|
||||
private class HitInfo
|
||||
{
|
||||
@ -284,30 +282,18 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
|
||||
#region RECOIL
|
||||
float hitRecoilAverage = 0;
|
||||
bool shouldIgnoreDetection = false;
|
||||
try
|
||||
{
|
||||
shouldIgnoreDetection = Plugin.Config.Configuration().AnticheatConfiguration.IgnoredDetectionSpecification[hit.GameName][DetectionType.Recoil]
|
||||
.Any(_weaponRegex => Regex.IsMatch(hit.Weapon.ToString(), _weaponRegex));
|
||||
}
|
||||
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (!shouldIgnoreDetection)
|
||||
if (!Plugin.Config.Configuration().RecoilessWeapons.Any(_weaponRegex => Regex.IsMatch(hit.Weapon.ToString(), _weaponRegex)))
|
||||
{
|
||||
validRecoilHitCount++;
|
||||
hitRecoilAverage = (hit.AnglesList.Sum(_angle => _angle.Z) + hit.ViewAngles.Z) / (hit.AnglesList.Count + 1);
|
||||
mapAverageRecoilAmount = (mapAverageRecoilAmount * (validRecoilHitCount - 1) + hitRecoilAverage) / validRecoilHitCount;
|
||||
sessionAverageRecoilAmount = (sessionAverageRecoilAmount * (validRecoilHitCount - 1) + hitRecoilAverage) / validRecoilHitCount;
|
||||
|
||||
if (validRecoilHitCount >= Thresholds.LowSampleMinKills && Kills > Thresholds.LowSampleMinKillsRecoil && mapAverageRecoilAmount == 0)
|
||||
if (validRecoilHitCount >= Thresholds.LowSampleMinKills && Kills > Thresholds.LowSampleMinKillsRecoil && sessionAverageRecoilAmount == 0)
|
||||
{
|
||||
results.Add(new DetectionPenaltyResult()
|
||||
{
|
||||
ClientPenalty = EFPenalty.PenaltyType.Ban,
|
||||
Value = mapAverageRecoilAmount,
|
||||
Value = sessionAverageRecoilAmount,
|
||||
HitCount = HitCount,
|
||||
Type = DetectionType.Recoil
|
||||
});
|
||||
@ -315,37 +301,6 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region BUTTON
|
||||
try
|
||||
{
|
||||
shouldIgnoreDetection = false;
|
||||
shouldIgnoreDetection = Plugin.Config.Configuration().AnticheatConfiguration.IgnoredDetectionSpecification[hit.GameName][DetectionType.Button]
|
||||
.Any(_weaponRegex => Regex.IsMatch(hit.Weapon.ToString(), _weaponRegex));
|
||||
}
|
||||
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (!shouldIgnoreDetection)
|
||||
{
|
||||
validButtonHitCount++;
|
||||
}
|
||||
|
||||
double lastDiff = hit.TimeOffset - hit.TimeSinceLastAttack;
|
||||
if (validButtonHitCount > 0 && lastDiff <= 0)
|
||||
{
|
||||
results.Add(new DetectionPenaltyResult()
|
||||
{
|
||||
ClientPenalty = EFPenalty.PenaltyType.Ban,
|
||||
Value = lastDiff,
|
||||
HitCount = HitCount,
|
||||
Type = DetectionType.Button
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SESSION_RATIOS
|
||||
if (Kills >= Thresholds.LowSampleMinKills)
|
||||
{
|
||||
@ -429,19 +384,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
#region CHEST_ABDOMEN_RATIO_SESSION
|
||||
int chestHits = HitLocationCount[IW4Info.HitLocation.torso_upper].Count;
|
||||
|
||||
try
|
||||
{
|
||||
shouldIgnoreDetection = false; // reset previous value
|
||||
shouldIgnoreDetection = Plugin.Config.Configuration().AnticheatConfiguration.IgnoredDetectionSpecification[hit.GameName][DetectionType.Chest]
|
||||
.Any(_weaponRegex => Regex.IsMatch(hit.Weapon.ToString(), _weaponRegex));
|
||||
}
|
||||
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (chestHits >= Thresholds.MediumSampleMinKills && !shouldIgnoreDetection)
|
||||
if (chestHits >= Thresholds.MediumSampleMinKills)
|
||||
{
|
||||
double marginOfError = Thresholds.GetMarginOfError(chestHits);
|
||||
double lerpAmount = Math.Min(1.0, (chestHits - Thresholds.MediumSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills));
|
||||
@ -523,11 +466,5 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public void OnMapChange()
|
||||
{
|
||||
mapAverageRecoilAmount = 0;
|
||||
validRecoilHitCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using static IW4MAdmin.Plugins.Stats.Cheat.Detection;
|
||||
using static SharedLibraryCore.Server;
|
||||
|
||||
namespace Stats.Config
|
||||
{
|
||||
public class AnticheatConfiguration
|
||||
{
|
||||
public bool Enable { get; set; }
|
||||
public IDictionary<long, DetectionType[]> ServerDetectionTypes { get; set; } = new Dictionary<long, DetectionType[]>();
|
||||
public IList<long> IgnoredClientIds { get; set; } = new List<long>();
|
||||
public IDictionary<Game, IDictionary<DetectionType, string[]>> IgnoredDetectionSpecification{ get; set; } = new Dictionary<Game, IDictionary<DetectionType, string[]>>
|
||||
{
|
||||
{
|
||||
Game.IW4, new Dictionary<DetectionType, string[]>
|
||||
{
|
||||
{ DetectionType.Chest, new[] { "m21.+" } },
|
||||
{ DetectionType.Recoil, new[] { "ranger.*_mp", "model1887.*_mp", ".+shotgun.*_mp" } },
|
||||
{ DetectionType.Button, new[] { ".*akimbo.*" } }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using Stats.Config;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static IW4MAdmin.Plugins.Stats.Cheat.Detection;
|
||||
|
||||
@ -9,41 +8,21 @@ namespace IW4MAdmin.Plugins.Stats.Config
|
||||
{
|
||||
public class StatsConfiguration : IBaseConfiguration
|
||||
{
|
||||
[Obsolete]
|
||||
public bool? EnableAntiCheat { get; set; }
|
||||
public bool EnableAntiCheat { get; set; }
|
||||
public List<StreakMessageConfiguration> KillstreakMessages { get; set; }
|
||||
public List<StreakMessageConfiguration> DeathstreakMessages { get; set; }
|
||||
public List<string> RecoilessWeapons { get; set; }
|
||||
public int TopPlayersMinPlayTime { get; set; }
|
||||
public bool StoreClientKills { get; set; }
|
||||
public int MostKillsMaxInactivityDays { get; set; } = 30;
|
||||
public int MostKillsClientLimit { get; set; } = 5;
|
||||
[Obsolete]
|
||||
public IDictionary<DetectionType, DistributionConfiguration> DetectionDistributions { get; set; }
|
||||
public IDictionary<long, DetectionType[]> ServerDetectionTypes { get; set; }
|
||||
public AnticheatConfiguration AnticheatConfiguration { get; set; } = new AnticheatConfiguration();
|
||||
|
||||
#pragma warning disable CS0612 // Type or member is obsolete
|
||||
public void ApplyMigration()
|
||||
{
|
||||
if (ServerDetectionTypes != null)
|
||||
{
|
||||
AnticheatConfiguration.ServerDetectionTypes = ServerDetectionTypes;
|
||||
}
|
||||
|
||||
ServerDetectionTypes = null;
|
||||
|
||||
if (EnableAntiCheat != null)
|
||||
{
|
||||
AnticheatConfiguration.Enable = EnableAntiCheat.Value;
|
||||
}
|
||||
|
||||
EnableAntiCheat = null;
|
||||
}
|
||||
#pragma warning restore CS0612 // Type or member is obsolete
|
||||
|
||||
public string Name() => "StatsPluginSettings";
|
||||
public IBaseConfiguration Generate()
|
||||
{
|
||||
AnticheatConfiguration.Enable = Utilities.PromptBool(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_SETUP_ENABLEAC"]);
|
||||
EnableAntiCheat = Utilities.PromptBool(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_SETUP_ENABLEAC"]);
|
||||
KillstreakMessages = new List<StreakMessageConfiguration>()
|
||||
{
|
||||
new StreakMessageConfiguration(){
|
||||
@ -78,9 +57,16 @@ namespace IW4MAdmin.Plugins.Stats.Config
|
||||
},
|
||||
};
|
||||
|
||||
RecoilessWeapons = new List<string>()
|
||||
{
|
||||
"ranger.*_mp",
|
||||
"model1887.*_mp",
|
||||
".+shotgun.*_mp"
|
||||
};
|
||||
|
||||
TopPlayersMinPlayTime = 3600 * 3;
|
||||
StoreClientKills = false;
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -481,8 +481,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
IsKill = !isDamage,
|
||||
AnglesList = snapshotAngles,
|
||||
IsAlive = isAlive == "1",
|
||||
TimeSinceLastAttack = long.Parse(lastAttackTime),
|
||||
GameName = attacker.CurrentServer.GameName
|
||||
TimeSinceLastAttack = long.Parse(lastAttackTime)
|
||||
};
|
||||
|
||||
if (hit.HitLoc == IW4Info.HitLocation.shield)
|
||||
@ -540,7 +539,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
if (Plugin.Config.Configuration().AnticheatConfiguration.Enable && !attacker.IsBot && attacker.ClientId != victim.ClientId)
|
||||
if (Plugin.Config.Configuration().EnableAntiCheat && !attacker.IsBot && attacker.ClientId != victim.ClientId)
|
||||
{
|
||||
clientDetection.TrackedHits.Add(hit);
|
||||
|
||||
@ -556,12 +555,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
|
||||
if (oldestHit.IsAlive)
|
||||
{
|
||||
var result = DeterminePenaltyResult(clientDetection.ProcessHit(oldestHit), attacker);
|
||||
|
||||
if (!Utilities.IsDevelopment)
|
||||
{
|
||||
await ApplyPenalty(result, attacker);
|
||||
}
|
||||
var result = DeterminePenaltyResult(clientDetection.ProcessHit(oldestHit), attacker.CurrentServer.EndPoint);
|
||||
#if !DEBUG
|
||||
await ApplyPenalty(result, attacker);
|
||||
#endif
|
||||
|
||||
if (clientDetection.Tracker.HasChanges && result.ClientPenalty != EFPenalty.PenaltyType.Any)
|
||||
{
|
||||
@ -597,10 +594,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
private DetectionPenaltyResult DeterminePenaltyResult(IEnumerable<DetectionPenaltyResult> results, EFClient client)
|
||||
private DetectionPenaltyResult DeterminePenaltyResult(IEnumerable<DetectionPenaltyResult> results, long serverId)
|
||||
{
|
||||
// allow disabling of certain detection types
|
||||
results = results.Where(_result => ShouldUseDetection(client.CurrentServer, _result.Type, client.ClientId));
|
||||
results = results.Where(_result => ShouldUseDetection(serverId, _result.Type));
|
||||
return results.FirstOrDefault(_result => _result.ClientPenalty == EFPenalty.PenaltyType.Ban) ??
|
||||
results.FirstOrDefault(_result => _result.ClientPenalty == EFPenalty.PenaltyType.Flag) ??
|
||||
new DetectionPenaltyResult()
|
||||
@ -620,31 +617,21 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldUseDetection(Server server, DetectionType detectionType, long clientId)
|
||||
private bool ShouldUseDetection(long serverId, DetectionType detectionType)
|
||||
{
|
||||
var detectionTypes = Plugin.Config.Configuration().AnticheatConfiguration.ServerDetectionTypes;
|
||||
var ignoredClients = Plugin.Config.Configuration().AnticheatConfiguration.IgnoredClientIds;
|
||||
var detectionTypes = Plugin.Config.Configuration().ServerDetectionTypes;
|
||||
|
||||
if (ignoredClients.Contains(clientId))
|
||||
if (detectionTypes == null)
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
if (!detectionTypes.ContainsKey(serverId))
|
||||
{
|
||||
if (detectionTypes[server.EndPoint].Contains(detectionType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
return detectionTypes[serverId].Contains(detectionType);
|
||||
}
|
||||
|
||||
async Task ApplyPenalty(DetectionPenaltyResult penalty, EFClient attacker)
|
||||
@ -1152,15 +1139,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
|
||||
public void ResetKillstreaks(Server sv)
|
||||
{
|
||||
foreach (var session in sv.GetClientsAsList()
|
||||
.Select(_client => new
|
||||
{
|
||||
stat = _client.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY),
|
||||
detection = _client.GetAdditionalProperty<Detection>(CLIENT_DETECTIONS_KEY)
|
||||
}))
|
||||
foreach (var stat in sv.GetClientsAsList()
|
||||
.Select(_client => _client.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY)))
|
||||
{
|
||||
session.stat?.StartNewSession();
|
||||
session.detection?.OnMapChange();
|
||||
stat?.StartNewSession();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1250,7 +1232,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
return 886229536;
|
||||
}
|
||||
|
||||
// todo: this is not stable and will need to be migrated again...
|
||||
long id = HashCode.Combine(server.IP, server.Port);
|
||||
id = id < 0 ? Math.Abs(id) : id;
|
||||
long? serverId;
|
||||
|
@ -5,7 +5,6 @@ using System.ComponentModel.DataAnnotations.Schema;
|
||||
using SharedLibraryCore.Helpers;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Collections.Generic;
|
||||
using static SharedLibraryCore.Server;
|
||||
|
||||
namespace IW4MAdmin.Plugins.Stats.Models
|
||||
{
|
||||
@ -45,8 +44,6 @@ namespace IW4MAdmin.Plugins.Stats.Models
|
||||
public float AdsPercent { get; set; }
|
||||
[NotMapped]
|
||||
public List<Vector3> AnglesList { get; set; }
|
||||
[NotMapped]
|
||||
public Game GameName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the attacker was alive after last captured angle
|
||||
|
@ -182,9 +182,8 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
if (Config.Configuration() == null)
|
||||
{
|
||||
Config.Set((StatsConfiguration)new StatsConfiguration().Generate());
|
||||
await Config.Save();
|
||||
}
|
||||
Config.Configuration().ApplyMigration();
|
||||
await Config.Save();
|
||||
|
||||
// register the topstats page
|
||||
// todo:generate the URL/Location instead of hardcoding
|
||||
@ -406,7 +405,7 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
return (await _chatQueryHelper.QueryResource(query)).Results;
|
||||
}
|
||||
|
||||
if (Config.Configuration().AnticheatConfiguration.Enable)
|
||||
if (Config.Configuration().EnableAntiCheat)
|
||||
{
|
||||
_metaService.AddRuntimeMeta<ClientPaginationRequest, InformationResponse>(MetaType.Information, getAnticheatInfo);
|
||||
}
|
||||
@ -497,6 +496,6 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <returns></returns>
|
||||
private bool ShouldOverrideAnticheatSetting(Server s) => Config.Configuration().AnticheatConfiguration.Enable && s.GameName == Server.Game.IW5;
|
||||
private bool ShouldOverrideAnticheatSetting(Server s) => Config.Configuration().EnableAntiCheat && s.GameName == Server.Game.IW5;
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ using SharedLibraryCore.Commands;
|
||||
using SharedLibraryCore.Configuration;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using static SharedLibraryCore.Server;
|
||||
|
||||
namespace SharedLibraryCore
|
||||
{
|
||||
@ -14,7 +13,7 @@ namespace SharedLibraryCore
|
||||
/// </summary>
|
||||
public abstract class Command : IManagerCommand
|
||||
{
|
||||
protected readonly CommandConfiguration _config;
|
||||
private readonly CommandConfiguration _config;
|
||||
protected readonly ITranslationLookup _translationLookup;
|
||||
protected ILogger logger;
|
||||
|
||||
@ -114,25 +113,6 @@ namespace SharedLibraryCore
|
||||
}
|
||||
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>
|
||||
/// Argument list for the command
|
||||
|
@ -772,6 +772,8 @@ namespace SharedLibraryCore.Commands
|
||||
/// </summary>
|
||||
public class ListAdminsCommand : Command
|
||||
{
|
||||
private readonly CommandConfiguration _config;
|
||||
|
||||
public ListAdminsCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
|
||||
{
|
||||
Name = "admins";
|
||||
@ -779,6 +781,8 @@ namespace SharedLibraryCore.Commands
|
||||
Alias = "a";
|
||||
Permission = Permission.User;
|
||||
RequiresTarget = false;
|
||||
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public static string OnlineAdmins(Server S, ITranslationLookup lookup)
|
||||
@ -897,6 +901,8 @@ namespace SharedLibraryCore.Commands
|
||||
/// </summary>
|
||||
public class ListRulesCommands : Command
|
||||
{
|
||||
private readonly CommandConfiguration _config;
|
||||
|
||||
public ListRulesCommands(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
|
||||
{
|
||||
Name = "rules";
|
||||
@ -904,6 +910,8 @@ namespace SharedLibraryCore.Commands
|
||||
Alias = "r";
|
||||
Permission = Permission.User;
|
||||
RequiresTarget = false;
|
||||
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public override Task ExecuteAsync(GameEvent E)
|
||||
|
@ -1,37 +0,0 @@
|
||||
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,7 +1,6 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using System.Text.Json.Serialization;
|
||||
using static SharedLibraryCore.Database.Models.EFClient;
|
||||
using static SharedLibraryCore.Server;
|
||||
|
||||
namespace SharedLibraryCore.Configuration
|
||||
{
|
||||
@ -30,11 +29,5 @@ namespace SharedLibraryCore.Configuration
|
||||
/// Indicates if the command can be run by another user (impersonation)
|
||||
/// </summary>
|
||||
public bool AllowImpersonation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the games supporting the functionality of the command
|
||||
/// </summary>
|
||||
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
|
||||
public Game[] SupportedGames { get; set; } = new Game[0];
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
namespace SharedLibraryCore.Dtos.Meta.Responses
|
||||
using System;
|
||||
|
||||
namespace SharedLibraryCore.Dtos.Meta.Responses
|
||||
{
|
||||
public class UpdatedAliasResponse : BaseMetaResponse
|
||||
{
|
||||
@ -15,6 +17,6 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => $"{Name.StripColors()}{IPAddress}".GetStableHashCode();
|
||||
public override int GetHashCode() => HashCode.Combine(Name.StripColors(), IPAddress);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
using System.Threading.Tasks;
|
||||
using static SharedLibraryCore.Database.Models.EFClient;
|
||||
using static SharedLibraryCore.Server;
|
||||
|
||||
namespace SharedLibraryCore.Interfaces
|
||||
{
|
||||
@ -36,11 +35,6 @@ namespace SharedLibraryCore.Interfaces
|
||||
/// </summary>
|
||||
Permission Permission { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Games the command is supported on
|
||||
/// </summary>
|
||||
Game[] SupportedGames { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Syntax for using the command
|
||||
/// </summary>
|
||||
|
@ -15,10 +15,9 @@ namespace SharedLibraryCore.Interfaces
|
||||
/// <param name="alias">alias of command</param>
|
||||
/// <param name="description">description of command</param>
|
||||
/// <param name="permission">minimum required permission</param>
|
||||
/// <param name="isTargetRequired">target required or not</param>
|
||||
/// <param name="args">command arguments (name, is required)</param>
|
||||
/// <param name="executeAction">action to peform when commmand is executed</param>
|
||||
/// <returns></returns>
|
||||
IManagerCommand CreateScriptCommand(string name, string alias, string description, string permission, bool isTargetRequired, IEnumerable<(string, bool)> args, Action<GameEvent> executeAction);
|
||||
IManagerCommand CreateScriptCommand(string name, string alias, string description, string permission, IEnumerable<(string, bool)> args, Action<GameEvent> executeAction);
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SharedLibraryCore.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// interface used to dynamically resolve services by string name
|
||||
/// </summary>
|
||||
public interface IScriptPluginServiceResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// resolves a service with the given name
|
||||
/// </summary>
|
||||
/// <param name="serviceName">class name of service</param>
|
||||
/// <returns></returns>
|
||||
object ResolveService(string serviceName);
|
||||
|
||||
/// <summary>
|
||||
/// resolves a service with the given name and generic params
|
||||
/// </summary>
|
||||
/// <param name="serviceName">class name of service</param>
|
||||
/// <param name="genericParams">generic class names</param>
|
||||
/// <returns></returns>
|
||||
object ResolveService(string serviceName, string[] genericParameters);
|
||||
}
|
||||
}
|
@ -657,8 +657,6 @@ namespace SharedLibraryCore.Database.Models
|
||||
[NotMapped]
|
||||
public bool IsBot => NetworkId == Name.GenerateGuidFromString();
|
||||
[NotMapped]
|
||||
public bool IsZombieClient => IsBot && Name == "Zombie";
|
||||
[NotMapped]
|
||||
public string XuidString => (NetworkId + 0x110000100000000).ToString("x");
|
||||
[NotMapped]
|
||||
public string GuidString => NetworkId.ToString("x");
|
||||
|
@ -6,7 +6,7 @@
|
||||
<ApplicationIcon />
|
||||
<StartupObject />
|
||||
<PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId>
|
||||
<Version>2.4.10</Version>
|
||||
<Version>2.4.9</Version>
|
||||
<Authors>RaidMax</Authors>
|
||||
<Company>Forever None</Company>
|
||||
<Configurations>Debug;Release;Prerelease</Configurations>
|
||||
@ -21,8 +21,8 @@
|
||||
<IsPackable>true</IsPackable>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<Description>Shared Library for IW4MAdmin</Description>
|
||||
<AssemblyVersion>2.4.10.0</AssemblyVersion>
|
||||
<FileVersion>2.4.10.0</FileVersion>
|
||||
<AssemblyVersion>2.4.9.0</AssemblyVersion>
|
||||
<FileVersion>2.4.9.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prerelease|AnyCPU'">
|
||||
|
@ -369,27 +369,7 @@ namespace SharedLibraryCore
|
||||
/// </summary>
|
||||
/// <param name="value">value string</param>
|
||||
/// <returns></returns>
|
||||
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 long GenerateGuidFromString(this string value) => string.IsNullOrEmpty(value) ? -1 : HashCode.Combine(value.StripColors());
|
||||
|
||||
public static int? ConvertToIP(this string str)
|
||||
{
|
||||
@ -793,8 +773,6 @@ namespace SharedLibraryCore
|
||||
byte[] bytes = toTest.GetAddressBytes();
|
||||
switch (bytes[0])
|
||||
{
|
||||
case 0:
|
||||
return bytes[1] == 0 && bytes[2] == 0 && bytes[3] == 0;
|
||||
case 10:
|
||||
return true;
|
||||
case 172:
|
||||
@ -976,7 +954,7 @@ namespace SharedLibraryCore
|
||||
/// <summary>
|
||||
/// wrapper method for humanizee that uses current current culture
|
||||
/// </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)
|
||||
{
|
||||
return timeSpan.Humanize(precision, CurrentLocalization.Culture, maxUnit, minUnit, collectionSeparator, toWords);
|
||||
|
@ -537,46 +537,5 @@ namespace ApplicationTests
|
||||
Assert.IsTrue(result.IsBroadcast);
|
||||
}
|
||||
#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
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
namespace ApplicationTests.Mocks
|
||||
{
|
||||
public interface IScriptResolverMock
|
||||
{
|
||||
string Value { get; set; }
|
||||
}
|
||||
|
||||
public class ScriptResolverMock : IScriptResolverMock
|
||||
{
|
||||
public string Value { get; set; }
|
||||
}
|
||||
public interface IScriptResolverGenericMock<T, V>
|
||||
{
|
||||
T Value { get; set; }
|
||||
V Value2 { get; set; }
|
||||
}
|
||||
|
||||
public class ScriptResolverGenericMock<T, V> : IScriptResolverGenericMock<T, V>
|
||||
{
|
||||
public T Value { get; set; }
|
||||
public V Value2 { get; set; }
|
||||
}
|
||||
}
|
@ -33,7 +33,6 @@ namespace ApplicationTests
|
||||
serviceProvider = new ServiceCollection().BuildBase()
|
||||
.AddSingleton(A.Fake<ClientService>())
|
||||
.AddSingleton<IScriptCommandFactory, ScriptCommandFactory>()
|
||||
.AddSingleton(A.Fake<IScriptPluginServiceResolver>())
|
||||
.BuildServiceProvider();
|
||||
fakeManager = serviceProvider.GetRequiredService<IManager>();
|
||||
mockEventHandler = serviceProvider.GetRequiredService<EventHandlerMock>();
|
||||
@ -67,7 +66,7 @@ namespace ApplicationTests
|
||||
A.CallTo(() => fakeManager.GetClientService())
|
||||
.Returns(fakeClientService);
|
||||
|
||||
await plugin.Initialize(serviceProvider.GetRequiredService<IManager>(), serviceProvider.GetRequiredService<IScriptCommandFactory>(), serviceProvider.GetRequiredService<IScriptPluginServiceResolver>());
|
||||
await plugin.Initialize(serviceProvider.GetRequiredService<IManager>(), serviceProvider.GetRequiredService<IScriptCommandFactory>());
|
||||
|
||||
var gameEvent = new GameEvent()
|
||||
{
|
||||
|
@ -1,66 +0,0 @@
|
||||
using ApplicationTests.Mocks;
|
||||
using IW4MAdmin.Application.Misc;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
|
||||
namespace ApplicationTests
|
||||
{
|
||||
public class ScriptPluginServiceResolverTests
|
||||
{
|
||||
private IServiceProvider serviceProvider;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
serviceProvider = new ServiceCollection()
|
||||
.BuildBase()
|
||||
.AddSingleton<ScriptPluginServiceResolver>()
|
||||
.AddSingleton<IScriptResolverMock, ScriptResolverMock>()
|
||||
.AddSingleton(new ScriptResolverMock { Value = "test" })
|
||||
.AddSingleton<IScriptResolverGenericMock<int, string>, ScriptResolverGenericMock<int,string>>()
|
||||
.AddSingleton(new ScriptResolverGenericMock<int, string> { Value = 123, Value2 = "test" })
|
||||
.BuildServiceProvider();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_ResolveType()
|
||||
{
|
||||
var resolver = serviceProvider.GetService<ScriptPluginServiceResolver>();
|
||||
var expectedResolvedService = serviceProvider.GetService<ScriptResolverMock>();
|
||||
var resolvedService = resolver.ResolveService(nameof(ScriptResolverMock));
|
||||
|
||||
Assert.AreEqual(expectedResolvedService, resolvedService);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_ResolveType_Interface()
|
||||
{
|
||||
var resolver = serviceProvider.GetService<ScriptPluginServiceResolver>();
|
||||
var expectedResolvedService = serviceProvider.GetService<IScriptResolverMock>();
|
||||
var resolvedService = resolver.ResolveService(nameof(IScriptResolverMock));
|
||||
|
||||
Assert.AreEqual(expectedResolvedService, resolvedService);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_ResolveGenericType()
|
||||
{
|
||||
var resolver = serviceProvider.GetService<ScriptPluginServiceResolver>();
|
||||
var expectedResolvedService = serviceProvider.GetService<ScriptResolverGenericMock<int, string>>();
|
||||
var resolvedService = resolver.ResolveService("ScriptResolverGenericMock", new[] { "Int32", "String" });
|
||||
|
||||
Assert.AreEqual(expectedResolvedService, resolvedService);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_ResolveGenericType_Interface()
|
||||
{
|
||||
var resolver = serviceProvider.GetService<ScriptPluginServiceResolver>();
|
||||
var expectedResolvedService = serviceProvider.GetService<IScriptResolverGenericMock<int, string>>();
|
||||
var resolvedService = resolver.ResolveService("IScriptResolverGenericMock", new[] { "Int32", "String" });
|
||||
|
||||
Assert.AreEqual(expectedResolvedService, resolvedService);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user