diff --git a/Application/EventParsers/BaseEventParser.cs b/Application/EventParsers/BaseEventParser.cs index fd154974..13e64fd1 100644 --- a/Application/EventParsers/BaseEventParser.cs +++ b/Application/EventParsers/BaseEventParser.cs @@ -7,6 +7,8 @@ using System.Collections.Generic; using System.Linq; using Data.Models; using Microsoft.Extensions.Logging; +using SharedLibraryCore.Events.Game; +using static System.Int32; using static SharedLibraryCore.Server; using ILogger = Microsoft.Extensions.Logging.ILogger; @@ -14,15 +16,19 @@ namespace IW4MAdmin.Application.EventParsers { public class BaseEventParser : IEventParser { - private readonly Dictionary)> _customEventRegistrations; + private readonly Dictionary)> + _customEventRegistrations; + private readonly ILogger _logger; private readonly ApplicationConfiguration _appConfig; private readonly Dictionary _regexMap; private readonly Dictionary _eventTypeMap; - public BaseEventParser(IParserRegexFactory parserRegexFactory, ILogger logger, ApplicationConfiguration appConfig) + public BaseEventParser(IParserRegexFactory parserRegexFactory, ILogger logger, + ApplicationConfiguration appConfig) { - _customEventRegistrations = new Dictionary)>(); + _customEventRegistrations = + new Dictionary)>(); _logger = logger; _appConfig = appConfig; @@ -50,7 +56,7 @@ namespace IW4MAdmin.Application.EventParsers Configuration.Join.AddMapping(ParserRegex.GroupType.OriginNetworkId, 2); Configuration.Join.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3); Configuration.Join.AddMapping(ParserRegex.GroupType.OriginName, 4); - + Configuration.JoinTeam.Pattern = @"^(JT);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);([0-9]+);(\w+);(.+)$"; Configuration.JoinTeam.AddMapping(ParserRegex.GroupType.EventType, 1); Configuration.JoinTeam.AddMapping(ParserRegex.GroupType.OriginNetworkId, 2); @@ -58,7 +64,8 @@ namespace IW4MAdmin.Application.EventParsers Configuration.JoinTeam.AddMapping(ParserRegex.GroupType.OriginTeam, 4); Configuration.JoinTeam.AddMapping(ParserRegex.GroupType.OriginName, 5); - Configuration.Damage.Pattern = @"^(D);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);(-?[0-9]+);(axis|allies|world|none)?;([^;]{1,32});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0)?;(-?[0-9]+);(axis|allies|world|none)?;([^;]{1,32})?;((?:[0-9]+|[a-z]+|_|\+)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$"; + Configuration.Damage.Pattern = + @"^(D);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);(-?[0-9]+);(axis|allies|world|none)?;([^;]{1,32});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0)?;(-?[0-9]+);(axis|allies|world|none)?;([^;]{1,32})?;((?:[0-9]+|[a-z]+|_|\+)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$"; Configuration.Damage.AddMapping(ParserRegex.GroupType.EventType, 1); Configuration.Damage.AddMapping(ParserRegex.GroupType.TargetNetworkId, 2); Configuration.Damage.AddMapping(ParserRegex.GroupType.TargetClientNumber, 3); @@ -73,7 +80,8 @@ namespace IW4MAdmin.Application.EventParsers Configuration.Damage.AddMapping(ParserRegex.GroupType.MeansOfDeath, 12); Configuration.Damage.AddMapping(ParserRegex.GroupType.HitLocation, 13); - Configuration.Kill.Pattern = @"^(K);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);(-?[0-9]+);(axis|allies|world|none)?;([^;]{1,32});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0)?;(-?[0-9]+);(axis|allies|world|none)?;([^;]{1,32})?;((?:[0-9]+|[a-z]+|_|\+)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$"; + Configuration.Kill.Pattern = + @"^(K);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);(-?[0-9]+);(axis|allies|world|none)?;([^;]{1,32});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0)?;(-?[0-9]+);(axis|allies|world|none)?;([^;]{1,32})?;((?:[0-9]+|[a-z]+|_|\+)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$"; Configuration.Kill.AddMapping(ParserRegex.GroupType.EventType, 1); Configuration.Kill.AddMapping(ParserRegex.GroupType.TargetNetworkId, 2); Configuration.Kill.AddMapping(ParserRegex.GroupType.TargetClientNumber, 3); @@ -95,24 +103,24 @@ namespace IW4MAdmin.Application.EventParsers _regexMap = new Dictionary { - {Configuration.Say, GameEvent.EventType.Say}, - {Configuration.Kill, GameEvent.EventType.Kill}, - {Configuration.MapChange, GameEvent.EventType.MapChange}, - {Configuration.MapEnd, GameEvent.EventType.MapEnd}, - {Configuration.JoinTeam, GameEvent.EventType.JoinTeam} + { Configuration.Say, GameEvent.EventType.Say }, + { Configuration.Kill, GameEvent.EventType.Kill }, + { Configuration.MapChange, GameEvent.EventType.MapChange }, + { Configuration.MapEnd, GameEvent.EventType.MapEnd }, + { Configuration.JoinTeam, GameEvent.EventType.JoinTeam } }; - + _eventTypeMap = new Dictionary { - {"say", GameEvent.EventType.Say}, - {"sayteam", GameEvent.EventType.Say}, - {"chat", GameEvent.EventType.Say}, - {"chatteam", GameEvent.EventType.Say}, - {"K", GameEvent.EventType.Kill}, - {"D", GameEvent.EventType.Damage}, - {"J", GameEvent.EventType.PreConnect}, - {"JT", GameEvent.EventType.JoinTeam}, - {"Q", GameEvent.EventType.PreDisconnect} + { "say", GameEvent.EventType.Say }, + { "sayteam", GameEvent.EventType.SayTeam }, + { "chat", GameEvent.EventType.Say }, + { "chatteam", GameEvent.EventType.SayTeam }, + { "K", GameEvent.EventType.Kill }, + { "D", GameEvent.EventType.Damage }, + { "J", GameEvent.EventType.PreConnect }, + { "JT", GameEvent.EventType.JoinTeam }, + { "Q", GameEvent.EventType.PreDisconnect } }; } @@ -126,28 +134,6 @@ namespace IW4MAdmin.Application.EventParsers public string Name { get; set; } = "Call of Duty"; - private (GameEvent.EventType type, string eventKey) GetEventTypeFromLine(string logLine) - { - var lineSplit = logLine.Split(';'); - if (lineSplit.Length > 1) - { - var type = lineSplit[0]; - return _eventTypeMap.ContainsKey(type) ? (_eventTypeMap[type], type): (GameEvent.EventType.Unknown, lineSplit[0]); - } - - foreach (var (key, value) in _regexMap) - { - var result = key.PatternMatcher.Match(logLine); - if (result.Success) - { - return (value, null); - } - } - - return (GameEvent.EventType.Unknown, null); - } - - public virtual GameEvent GenerateGameEvent(string logLine) { var timeMatch = Configuration.Time.PatternMatcher.Match(logLine); @@ -163,299 +149,44 @@ namespace IW4MAdmin.Application.EventParsers // this converts the timestamp into seconds passed .Select((value, index) => long.Parse(value.ToString()) * (index == 0 ? 60 : 1)) .Sum(); - } else { gameTime = long.Parse(timeMatch.Values[0]); } - + // we want to strip the time from the log line - logLine = logLine.Substring(timeMatch.Values.First().Length).Trim(); + logLine = logLine[timeMatch.Values.First().Length..].Trim(); } - var eventParseResult = GetEventTypeFromLine(logLine); - var eventType = eventParseResult.type; - - _logger.LogDebug(logLine); + var (eventType, eventKey) = GetEventTypeFromLine(logLine); - if (eventType == GameEvent.EventType.Say) + switch (eventType) { - var matchResult = Configuration.Say.PatternMatcher.Match(logLine); - - if (matchResult.Success) - { - var message = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.Message]] - .Replace(Configuration.LocalizeText, "") - .Trim(); - - if (message.Length > 0) - { - var originIdString = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginNetworkId]]; - var originName = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginName]]; - - var originId = originIdString.IsBotGuid() ? - originName.GenerateGuidFromString() : - originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle); - - var clientNumber = int.Parse(matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]); - - if (message.StartsWith(_appConfig.CommandPrefix) || message.StartsWith(_appConfig.BroadcastCommandPrefix)) - { - return new GameEvent() - { - Type = GameEvent.EventType.Command, - Data = message, - Origin = new EFClient() { NetworkId = originId, ClientNumber = clientNumber }, - Message = message, - Extra = logLine, - RequiredEntity = GameEvent.EventRequiredEntity.Origin, - GameTime = gameTime, - Source = GameEvent.EventSource.Log - }; - } - - return new GameEvent() - { - Type = GameEvent.EventType.Say, - Data = message, - Origin = new EFClient() { NetworkId = originId, ClientNumber = clientNumber }, - Message = message, - Extra = logLine, - RequiredEntity = GameEvent.EventRequiredEntity.Origin, - GameTime = gameTime, - Source = GameEvent.EventSource.Log - }; - } - } + case GameEvent.EventType.Say or GameEvent.EventType.SayTeam: + return ParseMessageEvent(logLine, gameTime, eventType) ?? GenerateDefaultEvent(logLine, gameTime); + case GameEvent.EventType.Kill: + return ParseKillEvent(logLine, gameTime) ?? GenerateDefaultEvent(logLine, gameTime); + case GameEvent.EventType.Damage: + return ParseDamageEvent(logLine, gameTime) ?? GenerateDefaultEvent(logLine, gameTime); + case GameEvent.EventType.PreConnect: + return ParseClientEnterMatchEvent(logLine, gameTime) ?? GenerateDefaultEvent(logLine, gameTime); + case GameEvent.EventType.JoinTeam: + return ParseJoinTeamEvent(logLine, gameTime) ?? GenerateDefaultEvent(logLine, gameTime); + case GameEvent.EventType.PreDisconnect: + return ParseClientExitMatchEvent(logLine, gameTime) ?? GenerateDefaultEvent(logLine, gameTime); + case GameEvent.EventType.MapEnd: + return ParseMatchEndEvent(logLine, gameTime); + case GameEvent.EventType.MapChange: + return ParseMatchStartEvent(logLine, gameTime); } - if (eventType == GameEvent.EventType.Kill) + if (eventKey is null || !_customEventRegistrations.ContainsKey(eventKey)) { - var match = Configuration.Kill.PatternMatcher.Match(logLine); - - if (match.Success) - { - var originIdString = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginNetworkId]]; - var targetIdString = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetNetworkId]]; - var originName = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginName]]; - var targetName = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetName]]; - - var originId = originIdString.IsBotGuid() ? - originName.GenerateGuidFromString() : - originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID); - var targetId = targetIdString.IsBotGuid() ? - targetName.GenerateGuidFromString() : - targetIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID); - - var originClientNumber = int.Parse(match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]); - var targetClientNumber = int.Parse(match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetClientNumber]]); - - return new GameEvent() - { - Type = GameEvent.EventType.Kill, - Data = logLine, - Origin = new EFClient() { NetworkId = originId, ClientNumber = originClientNumber }, - Target = new EFClient() { NetworkId = targetId, ClientNumber = targetClientNumber }, - RequiredEntity = GameEvent.EventRequiredEntity.Origin | GameEvent.EventRequiredEntity.Target, - GameTime = gameTime, - Source = GameEvent.EventSource.Log - }; - } + return GenerateDefaultEvent(logLine, gameTime); } - if (eventType == GameEvent.EventType.Damage) - { - var match = Configuration.Damage.PatternMatcher.Match(logLine); - - if (match.Success) - { - var originIdString = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginNetworkId]]; - var targetIdString = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetNetworkId]]; - var originName = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginName]]; - var targetName = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetName]]; - - var originId = originIdString.IsBotGuid() ? - originName.GenerateGuidFromString() : - originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID); - var targetId = targetIdString.IsBotGuid() ? - targetName.GenerateGuidFromString() : - targetIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID); - - var originClientNumber = int.Parse(match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]); - var targetClientNumber = int.Parse(match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetClientNumber]]); - - return new GameEvent() - { - Type = GameEvent.EventType.Damage, - Data = logLine, - Origin = new EFClient() { NetworkId = originId, ClientNumber = originClientNumber }, - Target = new EFClient() { NetworkId = targetId, ClientNumber = targetClientNumber }, - RequiredEntity = GameEvent.EventRequiredEntity.Origin | GameEvent.EventRequiredEntity.Target, - GameTime = gameTime, - Source = GameEvent.EventSource.Log - }; - } - } - - if (eventType == GameEvent.EventType.PreConnect) - { - var match = Configuration.Join.PatternMatcher.Match(logLine); - - if (match.Success) - { - var originIdString = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginNetworkId]]; - var originName = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginName]]; - - var networkId = originIdString.IsBotGuid() ? - originName.GenerateGuidFromString() : - originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle); - - return new GameEvent() - { - Type = GameEvent.EventType.PreConnect, - Data = logLine, - Origin = new EFClient() - { - CurrentAlias = new EFAlias() - { - Name = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginName]].TrimNewLine(), - }, - NetworkId = networkId, - ClientNumber = Convert.ToInt32(match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]), - State = EFClient.ClientState.Connecting, - }, - Extra = originIdString, - RequiredEntity = GameEvent.EventRequiredEntity.None, - IsBlocking = true, - GameTime = gameTime, - Source = GameEvent.EventSource.Log - }; - } - } - - if (eventType == GameEvent.EventType.JoinTeam) - { - var match = Configuration.JoinTeam.PatternMatcher.Match(logLine); - - if (match.Success) - { - var originIdString = match.Values[Configuration.JoinTeam.GroupMapping[ParserRegex.GroupType.OriginNetworkId]]; - var originName = match.Values[Configuration.JoinTeam.GroupMapping[ParserRegex.GroupType.OriginName]]; - var team = match.Values[Configuration.JoinTeam.GroupMapping[ParserRegex.GroupType.OriginTeam]]; - - if (Configuration.TeamMapping.ContainsKey(team)) - { - team = Configuration.TeamMapping[team].ToString(); - } - - var networkId = originIdString.IsBotGuid() ? - originName.GenerateGuidFromString() : - originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle); - - return new GameEvent - { - Type = GameEvent.EventType.JoinTeam, - Data = logLine, - Origin = new EFClient - { - CurrentAlias = new EFAlias - { - Name = match.Values[Configuration.JoinTeam.GroupMapping[ParserRegex.GroupType.OriginName]].TrimNewLine(), - }, - NetworkId = networkId, - ClientNumber = Convert.ToInt32(match.Values[Configuration.JoinTeam.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]), - State = EFClient.ClientState.Connected, - }, - Extra = team, - RequiredEntity = GameEvent.EventRequiredEntity.Origin, - GameTime = gameTime, - Source = GameEvent.EventSource.Log - }; - } - } - - if (eventType == GameEvent.EventType.PreDisconnect) - { - var match = Configuration.Quit.PatternMatcher.Match(logLine); - - if (match.Success) - { - var originIdString = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginNetworkId]]; - var originName = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginName]]; - - var networkId = originIdString.IsBotGuid() ? - originName.GenerateGuidFromString() : - originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle); - - return new GameEvent() - { - Type = GameEvent.EventType.PreDisconnect, - Data = logLine, - Origin = new EFClient() - { - CurrentAlias = new EFAlias() - { - Name = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginName]].TrimNewLine() - }, - NetworkId = networkId, - ClientNumber = Convert.ToInt32(match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]), - State = EFClient.ClientState.Disconnecting - }, - RequiredEntity = GameEvent.EventRequiredEntity.None, - IsBlocking = true, - GameTime = gameTime, - Source = GameEvent.EventSource.Log - }; - } - } - - if (eventType == GameEvent.EventType.MapEnd) - { - return new GameEvent() - { - Type = GameEvent.EventType.MapEnd, - Data = logLine, - Origin = Utilities.IW4MAdminClient(), - Target = Utilities.IW4MAdminClient(), - RequiredEntity = GameEvent.EventRequiredEntity.None, - GameTime = gameTime, - Source = GameEvent.EventSource.Log - }; - } - - if (eventType == GameEvent.EventType.MapChange) - { - var dump = logLine.Replace("InitGame: ", ""); - - return new GameEvent() - { - Type = GameEvent.EventType.MapChange, - Data = logLine, - Origin = Utilities.IW4MAdminClient(), - Target = Utilities.IW4MAdminClient(), - Extra = dump.DictionaryFromKeyValue(), - RequiredEntity = GameEvent.EventRequiredEntity.None, - GameTime = gameTime, - Source = GameEvent.EventSource.Log - }; - } - - if (eventParseResult.eventKey == null || !_customEventRegistrations.ContainsKey(eventParseResult.eventKey)) - { - return new GameEvent() - { - Type = GameEvent.EventType.Unknown, - Data = logLine, - Origin = Utilities.IW4MAdminClient(), - Target = Utilities.IW4MAdminClient(), - RequiredEntity = GameEvent.EventRequiredEntity.None, - GameTime = gameTime, - Source = GameEvent.EventSource.Log - }; - } - - var eventModifier = _customEventRegistrations[eventParseResult.eventKey]; + var eventModifier = _customEventRegistrations[eventKey]; try { @@ -469,12 +200,17 @@ namespace IW4MAdmin.Application.EventParsers }); } - catch (Exception e) + catch (Exception ex) { - _logger.LogError(e, "Could not handle custom event generation"); + _logger.LogError(ex, "Could not handle custom log event generation"); } - return new GameEvent() + return GenerateDefaultEvent(logLine, gameTime); + } + + private static GameEvent GenerateDefaultEvent(string logLine, long gameTime) + { + return new GameEvent { Type = GameEvent.EventType.Unknown, Data = logLine, @@ -486,8 +222,451 @@ namespace IW4MAdmin.Application.EventParsers }; } + private static GameEvent ParseMatchStartEvent(string logLine, long gameTime) + { + var dump = logLine.Replace("InitGame: ", "").DictionaryFromKeyValue(); + + return new MatchStartEvent + { + Type = GameEvent.EventType.MapChange, + Data = logLine, + Origin = Utilities.IW4MAdminClient(), + Target = Utilities.IW4MAdminClient(), + Extra = dump, + RequiredEntity = GameEvent.EventRequiredEntity.None, + GameTime = gameTime, + Source = GameEvent.EventSource.Log, + + // V2 + SessionData = dump + }; + } + + private static GameEvent ParseMatchEndEvent(string logLine, long gameTime) + { + return new MatchEndEvent + { + Type = GameEvent.EventType.MapEnd, + Data = logLine, + Origin = Utilities.IW4MAdminClient(), + Target = Utilities.IW4MAdminClient(), + RequiredEntity = GameEvent.EventRequiredEntity.None, + GameTime = gameTime, + Source = GameEvent.EventSource.Log, + + // V2 + SessionData = logLine + }; + } + + private GameEvent ParseClientExitMatchEvent(string logLine, long gameTime) + { + var match = Configuration.Quit.PatternMatcher.Match(logLine); + + if (!match.Success) + { + return null; + } + + var originIdString = + match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginNetworkId]]; + var originName = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginName]] + ?.TrimNewLine(); + var originClientNumber = + Convert.ToInt32( + match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]); + + var networkId = originIdString.IsBotGuid() + ? originName.GenerateGuidFromString() + : originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle); + + return new ClientExitMatchEvent + { + Type = GameEvent.EventType.PreDisconnect, + Data = logLine, + Origin = new EFClient + { + CurrentAlias = new EFAlias + { + Name = originName + }, + NetworkId = networkId, + ClientNumber = originClientNumber, + State = EFClient.ClientState.Disconnecting + }, + RequiredEntity = GameEvent.EventRequiredEntity.None, + IsBlocking = true, + GameTime = gameTime, + Source = GameEvent.EventSource.Log, + + // V2 + ClientName = originName, + ClientNetworkId = originIdString, + ClientSlotNumber = originClientNumber + }; + } + + private GameEvent? ParseJoinTeamEvent(string logLine, long gameTime) + { + var match = Configuration.JoinTeam.PatternMatcher.Match(logLine); + + if (!match.Success) + { + return null; + } + + var originIdString = + match.Values[Configuration.JoinTeam.GroupMapping[ParserRegex.GroupType.OriginNetworkId]]; + var originName = match.Values[Configuration.JoinTeam.GroupMapping[ParserRegex.GroupType.OriginName]] + ?.TrimNewLine(); + var team = match.Values[Configuration.JoinTeam.GroupMapping[ParserRegex.GroupType.OriginTeam]]; + var clientSlotNumber = + Parse(match.Values[ + Configuration.JoinTeam.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]); + + if (Configuration.TeamMapping.ContainsKey(team)) + { + team = Configuration.TeamMapping[team].ToString(); + } + + var networkId = originIdString.IsBotGuid() + ? originName.GenerateGuidFromString() + : originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle); + + return new ClientJoinTeamEvent + { + Type = GameEvent.EventType.JoinTeam, + Data = logLine, + Origin = new EFClient + { + CurrentAlias = new EFAlias + { + Name = originName + }, + NetworkId = networkId, + ClientNumber = clientSlotNumber, + State = EFClient.ClientState.Connected, + }, + Extra = team, + RequiredEntity = GameEvent.EventRequiredEntity.Origin, + GameTime = gameTime, + Source = GameEvent.EventSource.Log, + + // V2 + TeamName = team, + ClientName = originName, + ClientNetworkId = originIdString, + ClientSlotNumber = clientSlotNumber + }; + } + + private GameEvent? ParseClientEnterMatchEvent(string logLine, long gameTime) + { + var match = Configuration.Join.PatternMatcher.Match(logLine); + + if (!match.Success) + { + return null; + } + + var originIdString = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginNetworkId]]; + var originName = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginName]] + .TrimNewLine(); + var originClientNumber = + Convert.ToInt32( + match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]); + + var networkId = originIdString.IsBotGuid() + ? originName.GenerateGuidFromString() + : originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle); + + return new ClientEnterMatchEvent + { + Type = GameEvent.EventType.PreConnect, + Data = logLine, + Origin = new EFClient + { + CurrentAlias = new EFAlias + { + Name = originName + }, + NetworkId = networkId, + ClientNumber = originClientNumber, + State = EFClient.ClientState.Connecting, + }, + Extra = originIdString, + RequiredEntity = GameEvent.EventRequiredEntity.None, + IsBlocking = true, + GameTime = gameTime, + Source = GameEvent.EventSource.Log, + + // V2 + ClientName = originName, + ClientNetworkId = originIdString, + ClientSlotNumber = originClientNumber + }; + } + + #region DAMAGE + + private GameEvent? ParseDamageEvent(string logLine, long gameTime) + { + var match = Configuration.Damage.PatternMatcher.Match(logLine); + + if (!match.Success) + { + return null; + } + + var originIdString = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginNetworkId]]; + var targetIdString = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetNetworkId]]; + + var originName = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginName]] + ?.TrimNewLine(); + var targetName = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetName]] + ?.TrimNewLine(); + + var originId = originIdString.IsBotGuid() + ? originName.GenerateGuidFromString() + : originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID); + var targetId = targetIdString.IsBotGuid() + ? targetName.GenerateGuidFromString() + : targetIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID); + + var originClientNumber = + Parse(match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]); + var targetClientNumber = + Parse(match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetClientNumber]]); + + var originTeamName = + match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginTeam]]; + var targetTeamName = + match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetTeam]]; + + if (Configuration.TeamMapping.ContainsKey(originTeamName)) + { + originTeamName = Configuration.TeamMapping[originTeamName].ToString(); + } + + if (Configuration.TeamMapping.ContainsKey(targetTeamName)) + { + targetTeamName = Configuration.TeamMapping[targetTeamName].ToString(); + } + + var weaponName = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.Weapon]]; + TryParse(match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.Damage]], + out var damage); + var meansOfDeath = + match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.MeansOfDeath]]; + var hitLocation = + match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.HitLocation]]; + + return new ClientDamageEvent + { + Type = GameEvent.EventType.Damage, + Data = logLine, + Origin = new EFClient { NetworkId = originId, ClientNumber = originClientNumber }, + Target = new EFClient { NetworkId = targetId, ClientNumber = targetClientNumber }, + RequiredEntity = GameEvent.EventRequiredEntity.Origin | GameEvent.EventRequiredEntity.Target, + GameTime = gameTime, + Source = GameEvent.EventSource.Log, + + // V2 + ClientName = originName, + ClientNetworkId = originIdString, + ClientSlotNumber = originClientNumber, + AttackerTeamName = originTeamName, + VictimClientName = targetName, + VictimNetworkId = targetIdString, + VictimClientSlotNumber = targetClientNumber, + VictimTeamName = targetTeamName, + WeaponName = weaponName, + Damage = damage, + MeansOfDeath = meansOfDeath, + HitLocation = hitLocation + }; + } + + private GameEvent ParseKillEvent(string logLine, long gameTime) + { + var match = Configuration.Kill.PatternMatcher.Match(logLine); + + if (!match.Success) + { + return null; + } + + var originIdString = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginNetworkId]]; + var targetIdString = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetNetworkId]]; + + var originName = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginName]] + ?.TrimNewLine(); + var targetName = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetName]] + ?.TrimNewLine(); + + var originId = originIdString.IsBotGuid() + ? originName.GenerateGuidFromString() + : originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID); + var targetId = targetIdString.IsBotGuid() + ? targetName.GenerateGuidFromString() + : targetIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID); + + var originClientNumber = + Parse(match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]); + var targetClientNumber = + Parse(match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetClientNumber]]); + + var originTeamName = + match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginTeam]]; + var targetTeamName = + match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetTeam]]; + + if (Configuration.TeamMapping.ContainsKey(originTeamName)) + { + originTeamName = Configuration.TeamMapping[originTeamName].ToString(); + } + + if (Configuration.TeamMapping.ContainsKey(targetTeamName)) + { + targetTeamName = Configuration.TeamMapping[targetTeamName].ToString(); + } + + var weaponName = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.Weapon]]; + TryParse(match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.Damage]], + out var damage); + var meansOfDeath = + match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.MeansOfDeath]]; + var hitLocation = + match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.HitLocation]]; + + return new ClientKillEvent + { + Type = GameEvent.EventType.Kill, + Data = logLine, + Origin = new EFClient { NetworkId = originId, ClientNumber = originClientNumber }, + Target = new EFClient { NetworkId = targetId, ClientNumber = targetClientNumber }, + RequiredEntity = GameEvent.EventRequiredEntity.Origin | GameEvent.EventRequiredEntity.Target, + GameTime = gameTime, + Source = GameEvent.EventSource.Log, + + // V2 + ClientName = originName, + ClientNetworkId = originIdString, + ClientSlotNumber = originClientNumber, + AttackerTeamName = originTeamName, + VictimClientName = targetName, + VictimNetworkId = targetIdString, + VictimClientSlotNumber = targetClientNumber, + VictimTeamName = targetTeamName, + WeaponName = weaponName, + Damage = damage, + MeansOfDeath = meansOfDeath, + HitLocation = hitLocation + }; + } + + #endregion + + #region MESSAGE + + private GameEvent ParseMessageEvent(string logLine, long gameTime, GameEvent.EventType eventType) + { + var matchResult = Configuration.Say.PatternMatcher.Match(logLine); + + if (!matchResult.Success) + { + return null; + } + + var message = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.Message]] + .Replace(Configuration.LocalizeText, "") + .Trim(); + + if (message.Length <= 0) + { + return null; + } + + var originIdString = + matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginNetworkId]]; + var originName = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginName]] + ?.TrimNewLine(); + var clientNumber = + Parse(matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]); + + var originId = originIdString.IsBotGuid() + ? originName.GenerateGuidFromString() + : originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle); + + + if (message.StartsWith(_appConfig.CommandPrefix) || message.StartsWith(_appConfig.BroadcastCommandPrefix)) + { + return new ClientCommandEvent + { + Type = GameEvent.EventType.Command, + Data = message, + Origin = new EFClient { NetworkId = originId, ClientNumber = clientNumber }, + Message = message, + Extra = logLine, + RequiredEntity = GameEvent.EventRequiredEntity.Origin, + GameTime = gameTime, + Source = GameEvent.EventSource.Log, + + //V2 + ClientName = originName, + ClientNetworkId = originIdString, + ClientSlotNumber = clientNumber, + IsTeamMessage = eventType == GameEvent.EventType.SayTeam + }; + } + + return new ClientMessageEvent + { + Type = GameEvent.EventType.Say, + Data = message, + Origin = new EFClient { NetworkId = originId, ClientNumber = clientNumber }, + Message = message, + Extra = logLine, + RequiredEntity = GameEvent.EventRequiredEntity.Origin, + GameTime = gameTime, + Source = GameEvent.EventSource.Log, + + //V2 + ClientName = originName, + ClientNetworkId = originIdString, + ClientSlotNumber = clientNumber, + IsTeamMessage = eventType == GameEvent.EventType.SayTeam + }; + } + + #endregion + + private (GameEvent.EventType type, string eventKey) GetEventTypeFromLine(string logLine) + { + var lineSplit = logLine.Split(';'); + if (lineSplit.Length > 1) + { + var type = lineSplit[0]; + return _eventTypeMap.ContainsKey(type) + ? (_eventTypeMap[type], type) + : (GameEvent.EventType.Unknown, lineSplit[0]); + } + + foreach (var (key, value) in _regexMap) + { + var result = key.PatternMatcher.Match(logLine); + if (result.Success) + { + return (value, null); + } + } + + return (GameEvent.EventType.Unknown, null); + } + /// - public void RegisterCustomEvent(string eventSubtype, string eventTriggerValue, Func eventModifier) + public void RegisterCustomEvent(string eventSubtype, string eventTriggerValue, + Func eventModifier) { if (string.IsNullOrWhiteSpace(eventSubtype)) {