clean up the profanity determent plugin by using the Get/Set Additional properties

cleaned up the base event parser to not need the server object to generate the event
Hopefully prevent anticheat from freaking out when database connection is lost
This commit is contained in:
RaidMax 2019-05-13 10:36:11 -05:00
parent b99cc424e7
commit 5f588bb0f7
10 changed files with 169 additions and 212 deletions

View File

@ -75,27 +75,12 @@ namespace IW4MAdmin.Application.EventParsers
public string URLProtocolFormat { get; set; } = "CoD://{{ip}}:{{port}}"; public string URLProtocolFormat { get; set; } = "CoD://{{ip}}:{{port}}";
public virtual GameEvent GetEvent(Server server, string logLine) public virtual GameEvent GenerateGameEvent(string logLine)
{ {
logLine = Regex.Replace(logLine, @"([0-9]+:[0-9]+ |^[0-9]+ )", "").Trim(); logLine = Regex.Replace(logLine, @"([0-9]+:[0-9]+ |^[0-9]+ )", "").Trim();
string[] lineSplit = logLine.Split(';'); string[] lineSplit = logLine.Split(';');
string eventType = lineSplit[0]; string eventType = lineSplit[0];
// this is a "custom callback" event
if (eventType == "JoinTeam")
{
var origin = server.GetClientsAsList()
.FirstOrDefault(c => c.NetworkId == lineSplit[1].ConvertGuidToLong());
return new GameEvent()
{
Type = GameEvent.EventType.JoinTeam,
Data = logLine,
Origin = origin,
Owner = server
};
}
if (eventType == "say" || eventType == "sayteam") if (eventType == "say" || eventType == "sayteam")
{ {
var matchResult = Regex.Match(logLine, Configuration.Say.Pattern); var matchResult = Regex.Match(logLine, Configuration.Say.Pattern);
@ -110,8 +95,7 @@ namespace IW4MAdmin.Application.EventParsers
if (message.Length > 0) if (message.Length > 0)
{ {
var origin = server.GetClientsAsList() long originId = matchResult.Groups[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong();
.First(c => c.NetworkId == matchResult.Groups[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong());
if (message[0] == '!' || message[0] == '@') if (message[0] == '!' || message[0] == '@')
{ {
@ -119,8 +103,8 @@ namespace IW4MAdmin.Application.EventParsers
{ {
Type = GameEvent.EventType.Command, Type = GameEvent.EventType.Command,
Data = message, Data = message,
Origin = origin, Origin = new EFClient() { NetworkId = originId },
Owner = server, Target = Utilities.IW4MAdminClient(),
Message = message Message = message
}; };
} }
@ -129,8 +113,8 @@ namespace IW4MAdmin.Application.EventParsers
{ {
Type = GameEvent.EventType.Say, Type = GameEvent.EventType.Say,
Data = message, Data = message,
Origin = origin, Origin = new EFClient() { NetworkId = originId },
Owner = server, Target = Utilities.IW4MAdminClient(),
Message = message Message = message
}; };
} }
@ -139,111 +123,47 @@ namespace IW4MAdmin.Application.EventParsers
if (eventType == "K") if (eventType == "K")
{ {
if (!server.CustomCallback)
{
var match = Regex.Match(logLine, Configuration.Kill.Pattern); var match = Regex.Match(logLine, Configuration.Kill.Pattern);
if (match.Success) if (match.Success)
{ {
string originId = match.Groups[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].Value.ToString(); long originId = match.Groups[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].Value.ToString().ConvertGuidToLong(1);
string targetId = match.Groups[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].Value.ToString(); long targetId = match.Groups[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].Value.ToString().ConvertGuidToLong();
var origin = !string.IsNullOrEmpty(originId) ? server.GetClientsAsList()
.First(c => c.NetworkId == originId.ConvertGuidToLong()) :
Utilities.IW4MAdminClient(server);
var target = !string.IsNullOrEmpty(targetId) ? server.GetClientsAsList()
.First(c => c.NetworkId == targetId.ConvertGuidToLong()) :
Utilities.IW4MAdminClient(server);
return new GameEvent() return new GameEvent()
{ {
Type = GameEvent.EventType.Kill, Type = GameEvent.EventType.Kill,
Data = logLine, Data = logLine,
Origin = origin, Origin = new EFClient() { NetworkId = originId },
Target = target, Target = new EFClient() { NetworkId = targetId },
Owner = server
}; };
} }
} }
}
if (eventType == "ScriptKill")
{
long originId = lineSplit[1].ConvertGuidToLong();
long targetId = lineSplit[2].ConvertGuidToLong();
var origin = originId == long.MinValue ? Utilities.IW4MAdminClient(server) :
server.GetClientsAsList().First(c => c.NetworkId == originId);
var target = targetId == long.MinValue ? Utilities.IW4MAdminClient(server) :
server.GetClientsAsList().FirstOrDefault(c => c.NetworkId == targetId) ?? Utilities.IW4MAdminClient(server);
return new GameEvent()
{
Type = GameEvent.EventType.ScriptKill,
Data = logLine,
Origin = origin,
Target = target,
Owner = server
};
}
if (eventType == "ScriptDamage")
{
long originId = lineSplit[1].ConvertGuidToLong();
long targetId = lineSplit[2].ConvertGuidToLong();
var origin = originId == long.MinValue ? Utilities.IW4MAdminClient(server) :
server.GetClientsAsList().First(c => c.NetworkId == originId);
var target = targetId == long.MinValue ? Utilities.IW4MAdminClient(server) :
server.GetClientsAsList().FirstOrDefault(c => c.NetworkId == targetId) ?? Utilities.IW4MAdminClient(server);
return new GameEvent()
{
Type = GameEvent.EventType.ScriptDamage,
Data = logLine,
Origin = origin,
Target = target,
Owner = server
};
}
// damage
if (eventType == "D") if (eventType == "D")
{
if (!server.CustomCallback)
{ {
var regexMatch = Regex.Match(logLine, Configuration.Damage.Pattern); var regexMatch = Regex.Match(logLine, Configuration.Damage.Pattern);
if (regexMatch.Success) if (regexMatch.Success)
{ {
string originId = regexMatch.Groups[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString(); long originId = regexMatch.Groups[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(1);
string targetId = regexMatch.Groups[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].ToString(); long targetId = regexMatch.Groups[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].ToString().ConvertGuidToLong();
var origin = !string.IsNullOrEmpty(originId) ? server.GetClientsAsList()
.First(c => c.NetworkId == originId.ConvertGuidToLong()) :
Utilities.IW4MAdminClient(server);
var target = !string.IsNullOrEmpty(targetId) ? server.GetClientsAsList()
.First(c => c.NetworkId == targetId.ConvertGuidToLong()) :
Utilities.IW4MAdminClient(server);
return new GameEvent() return new GameEvent()
{ {
Type = GameEvent.EventType.Damage, Type = GameEvent.EventType.Damage,
Data = logLine, Data = logLine,
Origin = origin, Origin = new EFClient() { NetworkId = originId },
Target = target, Target = new EFClient() { NetworkId = targetId }
Owner = server
}; };
} }
} }
}
// join
if (eventType == "J") if (eventType == "J")
{ {
var regexMatch = Regex.Match(logLine, Configuration.Join.Pattern); var regexMatch = Regex.Match(logLine, Configuration.Join.Pattern);
if (regexMatch.Success) if (regexMatch.Success)
{ {
bool isBot = regexMatch.Groups[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().Contains("bot"); bool isBot = regexMatch.Groups[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().Contains("bot");
@ -252,7 +172,6 @@ namespace IW4MAdmin.Application.EventParsers
{ {
Type = GameEvent.EventType.PreConnect, Type = GameEvent.EventType.PreConnect,
Data = logLine, Data = logLine,
Owner = server,
Origin = new EFClient() Origin = new EFClient()
{ {
CurrentAlias = new EFAlias() CurrentAlias = new EFAlias()
@ -262,9 +181,9 @@ namespace IW4MAdmin.Application.EventParsers
NetworkId = regexMatch.Groups[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(), NetworkId = regexMatch.Groups[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(),
ClientNumber = Convert.ToInt32(regexMatch.Groups[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()), ClientNumber = Convert.ToInt32(regexMatch.Groups[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()),
State = EFClient.ClientState.Connecting, State = EFClient.ClientState.Connecting,
CurrentServer = server,
IsBot = isBot IsBot = isBot
} },
Target = Utilities.IW4MAdminClient()
}; };
} }
} }
@ -278,7 +197,6 @@ namespace IW4MAdmin.Application.EventParsers
{ {
Type = GameEvent.EventType.PreDisconnect, Type = GameEvent.EventType.PreDisconnect,
Data = logLine, Data = logLine,
Owner = server,
Origin = new EFClient() Origin = new EFClient()
{ {
CurrentAlias = new EFAlias() CurrentAlias = new EFAlias()
@ -288,7 +206,8 @@ namespace IW4MAdmin.Application.EventParsers
NetworkId = regexMatch.Groups[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(), NetworkId = regexMatch.Groups[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(),
ClientNumber = Convert.ToInt32(regexMatch.Groups[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()), ClientNumber = Convert.ToInt32(regexMatch.Groups[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()),
State = EFClient.ClientState.Disconnecting State = EFClient.ClientState.Disconnecting
} },
Target = Utilities.IW4MAdminClient()
}; };
} }
} }
@ -299,9 +218,8 @@ namespace IW4MAdmin.Application.EventParsers
{ {
Type = GameEvent.EventType.MapEnd, Type = GameEvent.EventType.MapEnd,
Data = lineSplit[0], Data = lineSplit[0],
Origin = Utilities.IW4MAdminClient(server), Origin = Utilities.IW4MAdminClient(),
Target = Utilities.IW4MAdminClient(server), Target = Utilities.IW4MAdminClient(),
Owner = server
}; };
} }
@ -313,19 +231,59 @@ namespace IW4MAdmin.Application.EventParsers
{ {
Type = GameEvent.EventType.MapChange, Type = GameEvent.EventType.MapChange,
Data = lineSplit[0], Data = lineSplit[0],
Origin = Utilities.IW4MAdminClient(server), Origin = Utilities.IW4MAdminClient(),
Target = Utilities.IW4MAdminClient(server), Target = Utilities.IW4MAdminClient(),
Owner = server,
Extra = dump.DictionaryFromKeyValue() Extra = dump.DictionaryFromKeyValue()
}; };
} }
// this is a custom event printed out by _customcallbacks.gsc (used for team balance)
if (eventType == "JoinTeam")
{
return new GameEvent()
{
Type = GameEvent.EventType.JoinTeam,
Data = logLine,
Origin = new EFClient() { NetworkId = lineSplit[1].ConvertGuidToLong() },
Target = Utilities.IW4MAdminClient()
};
}
// this is a custom event printed out by _customcallbacks.gsc (used for anticheat)
if (eventType == "ScriptKill")
{
long originId = lineSplit[1].ConvertGuidToLong(1);
long targetId = lineSplit[2].ConvertGuidToLong();
return new GameEvent()
{
Type = GameEvent.EventType.ScriptKill,
Data = logLine,
Origin = new EFClient() { NetworkId = originId },
Target = new EFClient() { NetworkId = targetId }
};
}
// this is a custom event printed out by _customcallbacks.gsc (used for anticheat)
if (eventType == "ScriptDamage")
{
long originId = lineSplit[1].ConvertGuidToLong(1);
long targetId = lineSplit[2].ConvertGuidToLong();
return new GameEvent()
{
Type = GameEvent.EventType.ScriptDamage,
Data = logLine,
Origin = new EFClient() { NetworkId = originId },
Target = new EFClient() { NetworkId = targetId }
};
}
return new GameEvent() return new GameEvent()
{ {
Type = GameEvent.EventType.Unknown, Type = GameEvent.EventType.Unknown,
Origin = Utilities.IW4MAdminClient(server), Origin = Utilities.IW4MAdminClient(),
Target = Utilities.IW4MAdminClient(server), Target = Utilities.IW4MAdminClient()
Owner = server
}; };
} }
} }

View File

@ -3,7 +3,7 @@ using SharedLibraryCore.Interfaces;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace IW4MAdmin.Application.IO namespace IW4MAdmin.Application.IO
@ -12,6 +12,7 @@ namespace IW4MAdmin.Application.IO
{ {
IEventParser Parser; IEventParser Parser;
readonly string LogFile; readonly string LogFile;
private bool? ignoreBots;
public long Length => new FileInfo(LogFile).Length; public long Length => new FileInfo(LogFile).Length;
@ -25,13 +26,17 @@ namespace IW4MAdmin.Application.IO
public async Task<ICollection<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition) public async Task<ICollection<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition)
{ {
if (!ignoreBots.HasValue)
{
ignoreBots = server.Manager.GetApplicationSettings().Configuration().IgnoreBots;
}
// allocate the bytes for the new log lines // allocate the bytes for the new log lines
List<string> logLines = new List<string>(); List<string> logLines = new List<string>();
// open the file as a stream // open the file as a stream
using (var rd = new StreamReader(new FileStream(LogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), Utilities.EncodingType)) using (var rd = new StreamReader(new FileStream(LogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), Utilities.EncodingType))
{ {
// todo: max async
// take the old start position and go back the number of new characters // take the old start position and go back the number of new characters
rd.BaseStream.Seek(-fileSizeDiff, SeekOrigin.End); rd.BaseStream.Seek(-fileSizeDiff, SeekOrigin.End);
@ -51,8 +56,25 @@ namespace IW4MAdmin.Application.IO
{ {
try try
{ {
// todo: catch elsewhere var gameEvent = Parser.GenerateGameEvent(eventLine);
events.Add(Parser.GetEvent(server, eventLine)); // we don't want to add the even if ignoreBots is on and the event comes froma bot
if (!ignoreBots.Value || (ignoreBots.Value && (gameEvent.Origin.NetworkId != -1 || gameEvent.Target.NetworkId != -1)))
{
gameEvent.Owner = server;
// we need to pull the "live" versions of the client (only if the client id isn't IW4MAdmin
gameEvent.Origin = gameEvent.Origin.ClientId == 1 ? gameEvent.Origin : server.GetClientsAsList().First(_client => _client.NetworkId == gameEvent.Origin.NetworkId);
gameEvent.Target = gameEvent.Target.ClientId == 1 ? gameEvent.Target : server.GetClientsAsList().First(_client => _client.NetworkId == gameEvent.Target.NetworkId);
events.Add(gameEvent);
}
}
catch (InvalidOperationException)
{
if (!ignoreBots.Value)
{
server.Logger.WriteWarning("Could not find client in client list when parsing event line");
}
} }
catch (Exception e) catch (Exception e)

View File

@ -4,6 +4,7 @@ using SharedLibraryCore;
using SharedLibraryCore.Interfaces; using SharedLibraryCore.Interfaces;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using static SharedLibraryCore.Utilities; using static SharedLibraryCore.Utilities;
@ -18,6 +19,7 @@ namespace IW4MAdmin.Application.IO
readonly IEventParser Parser; readonly IEventParser Parser;
readonly IGameLogServer Api; readonly IGameLogServer Api;
readonly string logPath; readonly string logPath;
private bool? ignoreBots;
public GameLogReaderHttp(Uri gameLogServerUri, string logPath, IEventParser parser) public GameLogReaderHttp(Uri gameLogServerUri, string logPath, IEventParser parser)
{ {
@ -35,6 +37,12 @@ namespace IW4MAdmin.Application.IO
#if DEBUG == true #if DEBUG == true
server.Logger.WriteDebug($"Begin reading from http log"); server.Logger.WriteDebug($"Begin reading from http log");
#endif #endif
if (!ignoreBots.HasValue)
{
ignoreBots = server.Manager.GetApplicationSettings().Configuration().IgnoreBots;
}
var events = new List<GameEvent>(); var events = new List<GameEvent>();
string b64Path = logPath; string b64Path = logPath;
var response = await Api.Log(b64Path); var response = await Api.Log(b64Path);
@ -52,16 +60,33 @@ namespace IW4MAdmin.Application.IO
{ {
try try
{ {
var e = Parser.GetEvent(server, eventLine); var gameEvent = Parser.GenerateGameEvent(eventLine);
// we don't want to add the even if ignoreBots is on and the event comes froma bot
if (!ignoreBots.Value || (ignoreBots.Value && (gameEvent.Origin.NetworkId != -1 || gameEvent.Target.NetworkId != -1)))
{
gameEvent.Owner = server;
// we need to pull the "live" versions of the client (only if the client id isn't IW4MAdmin
gameEvent.Origin = gameEvent.Origin.ClientId == 1 ? gameEvent.Origin : server.GetClientsAsList().First(_client => _client.NetworkId == gameEvent.Origin.NetworkId);
gameEvent.Target = gameEvent.Target.ClientId == 1 ? gameEvent.Target : server.GetClientsAsList().First(_client => _client.NetworkId == gameEvent.Target.NetworkId);
events.Add(gameEvent);
}
#if DEBUG == true #if DEBUG == true
server.Logger.WriteDebug($"Parsed event with id {e.Id} from http"); server.Logger.WriteDebug($"Parsed event with id {gameEvent.Id} from http");
#endif #endif
events.Add(e); }
catch (InvalidOperationException)
{
if (!ignoreBots.Value)
{
server.Logger.WriteWarning("Could not find client in client list when parsing event line");
}
} }
catch (Exception e) catch (Exception e)
{ {
server.Logger.WriteWarning("Could not properly parse event line"); server.Logger.WriteWarning("Could not properly parse remote event line");
server.Logger.WriteDebug(e.Message); server.Logger.WriteDebug(e.Message);
server.Logger.WriteDebug(eventLine); server.Logger.WriteDebug(eventLine);
} }

View File

@ -1,11 +1,9 @@
using System.Collections.Concurrent; using System.Linq;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using SharedLibraryCore; using SharedLibraryCore;
using SharedLibraryCore.Configuration; using SharedLibraryCore.Configuration;
using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Interfaces; using SharedLibraryCore.Interfaces;
namespace IW4MAdmin.Plugins.ProfanityDeterment namespace IW4MAdmin.Plugins.ProfanityDeterment
@ -19,8 +17,6 @@ namespace IW4MAdmin.Plugins.ProfanityDeterment
public string Author => "RaidMax"; public string Author => "RaidMax";
BaseConfigurationHandler<Configuration> Settings; BaseConfigurationHandler<Configuration> Settings;
ConcurrentDictionary<int, Tracking> ProfanityCounts;
IManager Manager;
public Task OnEventAsync(GameEvent E, Server S) public Task OnEventAsync(GameEvent E, Server S)
{ {
@ -29,10 +25,7 @@ namespace IW4MAdmin.Plugins.ProfanityDeterment
if (E.Type == GameEvent.EventType.Connect) if (E.Type == GameEvent.EventType.Connect)
{ {
if (!ProfanityCounts.TryAdd(E.Origin.ClientId, new Tracking(E.Origin))) E.Origin.SetAdditionalProperty("_profanityInfringements", 0);
{
S.Logger.WriteWarning("Could not add client to profanity tracking");
}
var objectionalWords = Settings.Configuration().OffensiveWords; var objectionalWords = Settings.Configuration().OffensiveWords;
bool containsObjectionalWord = objectionalWords.FirstOrDefault(w => E.Origin.Name.ToLower().Contains(w)) != null; bool containsObjectionalWord = objectionalWords.FirstOrDefault(w => E.Origin.Name.ToLower().Contains(w)) != null;
@ -54,10 +47,7 @@ namespace IW4MAdmin.Plugins.ProfanityDeterment
if (E.Type == GameEvent.EventType.Disconnect) if (E.Type == GameEvent.EventType.Disconnect)
{ {
if (!ProfanityCounts.TryRemove(E.Origin.ClientId, out Tracking old)) E.Origin.SetAdditionalProperty("_profanityInfringements", 0);
{
S.Logger.WriteWarning("Could not remove client from profanity tracking");
}
} }
if (E.Type == GameEvent.EventType.Say) if (E.Type == GameEvent.EventType.Say)
@ -78,17 +68,17 @@ namespace IW4MAdmin.Plugins.ProfanityDeterment
if (containsObjectionalWord) if (containsObjectionalWord)
{ {
var clientProfanity = ProfanityCounts[E.Origin.ClientId]; int profanityInfringments = E.Origin.GetAdditionalProperty<int>("_profanityInfringements");
if (clientProfanity.Infringements >= Settings.Configuration().KickAfterInfringementCount)
if (profanityInfringments >= Settings.Configuration().KickAfterInfringementCount)
{ {
clientProfanity.Client.Kick(Settings.Configuration().ProfanityKickMessage, Utilities.IW4MAdminClient(E.Owner)); E.Origin.Kick(Settings.Configuration().ProfanityKickMessage, Utilities.IW4MAdminClient(E.Owner));
} }
else if (clientProfanity.Infringements < Settings.Configuration().KickAfterInfringementCount) else if (profanityInfringments < Settings.Configuration().KickAfterInfringementCount)
{ {
clientProfanity.Infringements++; E.Origin.SetAdditionalProperty("_profanityInfringements", profanityInfringments + 1);
E.Origin.Warn(Settings.Configuration().ProfanityWarningMessage, Utilities.IW4MAdminClient(E.Owner));
clientProfanity.Client.Warn(Settings.Configuration().ProfanityWarningMessage, Utilities.IW4MAdminClient(E.Owner));
} }
} }
} }
@ -104,9 +94,6 @@ namespace IW4MAdmin.Plugins.ProfanityDeterment
Settings.Set((Configuration)new Configuration().Generate()); Settings.Set((Configuration)new Configuration().Generate());
await Settings.Save(); await Settings.Save();
} }
ProfanityCounts = new ConcurrentDictionary<int, Tracking>();
Manager = manager;
} }
public Task OnTickAsync(Server S) => Task.CompletedTask; public Task OnTickAsync(Server S) => Task.CompletedTask;

View File

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Objects;
namespace IW4MAdmin.Plugins.ProfanityDeterment
{
class Tracking
{
public EFClient Client { get; private set; }
public int Infringements { get; set; }
public Tracking(EFClient client)
{
Client = client;
Infringements = 0;
}
}
}

View File

@ -568,7 +568,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
ctx.Set<EFClientKill>().Add(hit); ctx.Set<EFClientKill>().Add(hit);
} }
if (Plugin.Config.Configuration().EnableAntiCheat && !attacker.IsBot) if (Plugin.Config.Configuration().EnableAntiCheat && !attacker.IsBot && attacker.ClientId != victim.ClientId)
{ {
if (clientDetection.QueuedHits.Count > Detection.QUEUE_COUNT) if (clientDetection.QueuedHits.Count > Detection.QUEUE_COUNT)
{ {
@ -577,8 +577,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
clientDetection.QueuedHits = clientDetection.QueuedHits.OrderBy(_hits => _hits.TimeOffset).ToList(); clientDetection.QueuedHits = clientDetection.QueuedHits.OrderBy(_hits => _hits.TimeOffset).ToList();
var oldestHit = clientDetection.QueuedHits.First(); var oldestHit = clientDetection.QueuedHits.First();
clientDetection.QueuedHits.RemoveAt(0); clientDetection.QueuedHits.RemoveAt(0);
await ApplyPenalty(clientDetection.ProcessHit(oldestHit, isDamage), clientDetection, attacker, ctx); await ApplyPenalty(clientDetection.ProcessHit(oldestHit, isDamage), attacker, ctx);
} }
await ApplyPenalty(clientDetection.ProcessTotalRatio(clientStats), attacker, ctx);
} }
else else
@ -586,7 +588,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
clientDetection.QueuedHits.Add(hit); clientDetection.QueuedHits.Add(hit);
} }
await ApplyPenalty(clientDetection.ProcessTotalRatio(clientStats), clientDetection, attacker, ctx); if (clientDetection.Tracker.HasChanges)
{
SaveTrackedSnapshots(clientDetection, ctx);
}
} }
ctx.Set<EFHitLocationCount>().UpdateRange(clientStats.HitLocations); ctx.Set<EFHitLocationCount>().UpdateRange(clientStats.HitLocations);
@ -604,7 +609,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
} }
} }
async Task ApplyPenalty(DetectionPenaltyResult penalty, Detection clientDetection, EFClient attacker, DatabaseContext ctx) async Task ApplyPenalty(DetectionPenaltyResult penalty, EFClient attacker, DatabaseContext ctx)
{ {
var penaltyClient = Utilities.IW4MAdminClient(attacker.CurrentServer); var penaltyClient = Utilities.IW4MAdminClient(attacker.CurrentServer);
switch (penalty.ClientPenalty) switch (penalty.ClientPenalty)
@ -626,11 +631,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
}; };
await attacker.Ban(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_CHEAT_DETECTED"], penaltyClient, false).WaitAsync(Utilities.DefaultCommandTimeout, attacker.CurrentServer.Manager.CancellationToken); await attacker.Ban(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_CHEAT_DETECTED"], penaltyClient, false).WaitAsync(Utilities.DefaultCommandTimeout, attacker.CurrentServer.Manager.CancellationToken);
if (clientDetection.Tracker.HasChanges)
{
SaveTrackedSnapshots(clientDetection, ctx);
}
break; break;
case Penalty.PenaltyType.Flag: case Penalty.PenaltyType.Flag:
if (attacker.Level != EFClient.Permission.User) if (attacker.Level != EFClient.Permission.User)
@ -643,11 +643,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
$"{penalty.Type}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}"; $"{penalty.Type}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}";
await attacker.Flag(flagReason, penaltyClient).WaitAsync(Utilities.DefaultCommandTimeout, attacker.CurrentServer.Manager.CancellationToken); await attacker.Flag(flagReason, penaltyClient).WaitAsync(Utilities.DefaultCommandTimeout, attacker.CurrentServer.Manager.CancellationToken);
if (clientDetection.Tracker.HasChanges)
{
SaveTrackedSnapshots(clientDetection, ctx);
}
break; break;
} }
} }
@ -655,7 +650,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
void SaveTrackedSnapshots(Detection clientDetection, DatabaseContext ctx) void SaveTrackedSnapshots(Detection clientDetection, DatabaseContext ctx)
{ {
// todo: why does this cause duplicate primary key // todo: why does this cause duplicate primary key
var change = clientDetection.Tracker.GetNextChange(); _ = clientDetection.Tracker.GetNextChange();
EFACSnapshot change;
while ((change = clientDetection.Tracker.GetNextChange()) != default(EFACSnapshot)) while ((change = clientDetection.Tracker.GetNextChange()) != default(EFACSnapshot))
{ {

View File

@ -80,16 +80,11 @@ namespace IW4MAdmin.Plugins.Stats
if (killInfo.Length >= 14 && !ShouldIgnoreEvent(E.Origin, E.Target)) if (killInfo.Length >= 14 && !ShouldIgnoreEvent(E.Origin, E.Target))
{ {
// this treats "world" damage as self damage // this treats "world" damage as self damage
if (E.Origin.ClientId <= 1) if (E.Origin.ClientId == 1)
{ {
E.Origin = E.Target; E.Origin = E.Target;
} }
if (E.Target.ClientId <= 1)
{
E.Target = E.Origin;
}
await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, await StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8], await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, await StatManager.GetIdForServer(E.Owner), 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[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]);
} }
@ -98,16 +93,11 @@ namespace IW4MAdmin.Plugins.Stats
if (!E.Owner.CustomCallback && !ShouldIgnoreEvent(E.Origin, E.Target)) if (!E.Owner.CustomCallback && !ShouldIgnoreEvent(E.Origin, E.Target))
{ {
// this treats "world" damage as self damage // this treats "world" damage as self damage
if (E.Origin.ClientId <= 1) if (E.Origin.ClientId == 1)
{ {
E.Origin = E.Target; E.Origin = E.Target;
} }
if (E.Target.ClientId <= 1)
{
E.Target = E.Origin;
}
await Manager.AddStandardKill(E.Origin, E.Target); await Manager.AddStandardKill(E.Origin, E.Target);
} }
break; break;
@ -115,16 +105,11 @@ namespace IW4MAdmin.Plugins.Stats
if (!E.Owner.CustomCallback && !ShouldIgnoreEvent(E.Origin, E.Target)) if (!E.Owner.CustomCallback && !ShouldIgnoreEvent(E.Origin, E.Target))
{ {
// this treats "world" damage as self damage // this treats "world" damage as self damage
if (E.Origin.ClientId <= 1) if (E.Origin.ClientId == 1)
{ {
E.Origin = E.Target; E.Origin = E.Target;
} }
if (E.Target.ClientId <= 1)
{
E.Target = E.Origin;
}
Manager.AddDamageEvent(E.Data, E.Origin.ClientId, E.Target.ClientId, await StatManager.GetIdForServer(E.Owner)); Manager.AddDamageEvent(E.Data, E.Origin.ClientId, E.Target.ClientId, await StatManager.GetIdForServer(E.Owner));
} }
break; break;
@ -133,16 +118,11 @@ namespace IW4MAdmin.Plugins.Stats
if (killInfo.Length >= 14 && !ShouldIgnoreEvent(E.Origin, E.Target)) if (killInfo.Length >= 14 && !ShouldIgnoreEvent(E.Origin, E.Target))
{ {
// this treats "world" damage as self damage // this treats "world" damage as self damage
if (E.Origin.ClientId <= 1) if (E.Origin.ClientId == 1)
{ {
E.Origin = E.Target; E.Origin = E.Target;
} }
if (E.Target.ClientId <= 1)
{
E.Target = E.Origin;
}
await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, await StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8], await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, await StatManager.GetIdForServer(E.Owner), 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[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]);
} }

View File

@ -7,11 +7,10 @@ namespace SharedLibraryCore.Interfaces
/// <summary> /// <summary>
/// Generates a game event based on log line input /// Generates a game event based on log line input
/// </summary> /// </summary>
/// <param name="server">server the event occurred on</param>
/// <param name="logLine">single log line string</param> /// <param name="logLine">single log line string</param>
/// <returns></returns> /// <returns></returns>
/// todo: make this integrate without needing the server /// todo: make this integrate without needing the server
GameEvent GetEvent(Server server, string logLine); GameEvent GenerateGameEvent(string logLine);
/// <summary> /// <summary>
/// Get game specific folder prefix for log files /// Get game specific folder prefix for log files
/// </summary> /// </summary>

View File

@ -268,11 +268,16 @@ namespace SharedLibraryCore
} }
} }
public static long ConvertGuidToLong(this string str) public static long ConvertGuidToLong(this string str, long? fallback = null)
{ {
str = str.Substring(0, Math.Min(str.Length, 16)); str = str.Substring(0, Math.Min(str.Length, 16));
var bot = Regex.Match(str, @"bot[0-9]+").Value; var bot = Regex.Match(str, @"bot[0-9]+").Value;
if (string.IsNullOrWhiteSpace(str) && fallback.HasValue)
{
return fallback.Value;
}
// this is a special case for Plutonium T6 // this is a special case for Plutonium T6
if (str.Length <= 11 && if (str.Length <= 11 &&
long.TryParse(str, NumberStyles.Integer, CultureInfo.InvariantCulture, out long id)) // 10 numeric characters + signed character long.TryParse(str, NumberStyles.Integer, CultureInfo.InvariantCulture, out long id)) // 10 numeric characters + signed character

View File

@ -121,6 +121,11 @@ namespace WebfrontCore.Controllers
public async Task<IActionResult> FindAsync(string clientName) public async Task<IActionResult> FindAsync(string clientName)
{ {
if (string.IsNullOrWhiteSpace(clientName))
{
return StatusCode(400);
}
var clientsDto = await Manager.GetClientService().FindClientsByIdentifier(clientName); var clientsDto = await Manager.GetClientService().FindClientsByIdentifier(clientName);
ViewBag.Title = $"{clientsDto.Count} {Localization["WEBFRONT_CLIENT_SEARCH_MATCHING"]} \"{clientName}\""; ViewBag.Title = $"{clientsDto.Count} {Localization["WEBFRONT_CLIENT_SEARCH_MATCHING"]} \"{clientName}\"";