From f567a03fa7229fb4b87793e8ea41e0435d282932 Mon Sep 17 00:00:00 2001 From: RaidMax Date: Sat, 12 Mar 2022 13:38:33 -0600 Subject: [PATCH] implement team tracking via game interface (EFClient.Team and EFClient.TeamName) --- Application/EventParsers/BaseEventParser.cs | 44 +++++++++++++++++++ .../DynamicEventParserConfiguration.cs | 4 +- Application/IO/NetworkGameLogReader.cs | 2 +- Application/IW4MServer.cs | 5 +++ .../IW4x/userraw/scripts/_integration.gsc | 2 +- .../Interfaces/IEventParserConfiguration.cs | 7 ++- SharedLibraryCore/PartialEntities/EFClient.cs | 22 ++++++++++ 7 files changed, 82 insertions(+), 4 deletions(-) diff --git a/Application/EventParsers/BaseEventParser.cs b/Application/EventParsers/BaseEventParser.cs index b0c3cf0de..28b975451 100644 --- a/Application/EventParsers/BaseEventParser.cs +++ b/Application/EventParsers/BaseEventParser.cs @@ -49,6 +49,13 @@ 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); + Configuration.JoinTeam.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3); + 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.AddMapping(ParserRegex.GroupType.EventType, 1); @@ -100,6 +107,7 @@ namespace IW4MAdmin.Application.EventParsers {"K", GameEvent.EventType.Kill}, {"D", GameEvent.EventType.Damage}, {"J", GameEvent.EventType.PreConnect}, + {"JT", GameEvent.EventType.JoinTeam }, {"Q", GameEvent.EventType.PreDisconnect}, }; } @@ -322,6 +330,42 @@ namespace IW4MAdmin.Application.EventParsers } } + 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]]; + + 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.None, + GameTime = gameTime, + Source = GameEvent.EventSource.Log + }; + } + } + if (eventType == GameEvent.EventType.PreDisconnect) { var match = Configuration.Quit.PatternMatcher.Match(logLine); diff --git a/Application/EventParsers/DynamicEventParserConfiguration.cs b/Application/EventParsers/DynamicEventParserConfiguration.cs index 59873bf14..d3815c429 100644 --- a/Application/EventParsers/DynamicEventParserConfiguration.cs +++ b/Application/EventParsers/DynamicEventParserConfiguration.cs @@ -8,11 +8,12 @@ namespace IW4MAdmin.Application.EventParsers /// generic implementation of the IEventParserConfiguration /// allows script plugins to generate dynamic configurations /// - sealed internal class DynamicEventParserConfiguration : IEventParserConfiguration + internal sealed class DynamicEventParserConfiguration : IEventParserConfiguration { public string GameDirectory { get; set; } public ParserRegex Say { get; set; } public ParserRegex Join { get; set; } + public ParserRegex JoinTeam { get; set; } public ParserRegex Quit { get; set; } public ParserRegex Kill { get; set; } public ParserRegex Damage { get; set; } @@ -26,6 +27,7 @@ namespace IW4MAdmin.Application.EventParsers { Say = parserRegexFactory.CreateParserRegex(); Join = parserRegexFactory.CreateParserRegex(); + JoinTeam = parserRegexFactory.CreateParserRegex(); Quit = parserRegexFactory.CreateParserRegex(); Kill = parserRegexFactory.CreateParserRegex(); Damage = parserRegexFactory.CreateParserRegex(); diff --git a/Application/IO/NetworkGameLogReader.cs b/Application/IO/NetworkGameLogReader.cs index a58ffa5da..9b81dc69c 100644 --- a/Application/IO/NetworkGameLogReader.cs +++ b/Application/IO/NetworkGameLogReader.cs @@ -89,7 +89,7 @@ namespace IW4MAdmin.Application.IO var lines = logData .Split('\n') - .Where(line => line.Length > 0); + .Where(line => line.Length > 0 && !line.Contains('ΓΏ')); foreach (var eventLine in lines) { diff --git a/Application/IW4MServer.cs b/Application/IW4MServer.cs index ad67d616c..bea9fe374 100644 --- a/Application/IW4MServer.cs +++ b/Application/IW4MServer.cs @@ -713,6 +713,11 @@ namespace IW4MAdmin await E.Owner.ExecuteCommandAsync(E.Data); } } + + else if (E.Type == GameEvent.EventType.JoinTeam) + { + E.Origin.UpdateTeam(E.Extra as string); + } lock (ChatHistory) { diff --git a/GameFiles/IW4x/userraw/scripts/_integration.gsc b/GameFiles/IW4x/userraw/scripts/_integration.gsc index 296ee6850..8d55bbb0a 100644 --- a/GameFiles/IW4x/userraw/scripts/_integration.gsc +++ b/GameFiles/IW4x/userraw/scripts/_integration.gsc @@ -623,7 +623,7 @@ UnhideImpl() return; } - if ( IsDefined( self.isHidden ) && !self.isHidden ) + if ( !IsDefined( self.isHidden ) || !self.isHidden ) { self IPrintLnBold( "You are not hidden" ); return; diff --git a/SharedLibraryCore/Interfaces/IEventParserConfiguration.cs b/SharedLibraryCore/Interfaces/IEventParserConfiguration.cs index d2cffc2d3..c08b58351 100644 --- a/SharedLibraryCore/Interfaces/IEventParserConfiguration.cs +++ b/SharedLibraryCore/Interfaces/IEventParserConfiguration.cs @@ -18,6 +18,11 @@ namespace SharedLibraryCore.Interfaces /// stores the regex information for a join event printed in the game log /// ParserRegex Join { get; set; } + + /// + /// stores the regex information for a join team event printed in the game log + /// + ParserRegex JoinTeam { get; set; } /// /// stores the regex information for a quit event printed in the game log @@ -59,4 +64,4 @@ namespace SharedLibraryCore.Interfaces /// NumberStyles GuidNumberStyle { get; set; } } -} \ No newline at end of file +} diff --git a/SharedLibraryCore/PartialEntities/EFClient.cs b/SharedLibraryCore/PartialEntities/EFClient.cs index 2c08e3e3d..5ade87603 100644 --- a/SharedLibraryCore/PartialEntities/EFClient.cs +++ b/SharedLibraryCore/PartialEntities/EFClient.cs @@ -39,6 +39,14 @@ namespace SharedLibraryCore.Database.Models Disconnecting } + public enum TeamType + { + Unknown, + Spectator, + Allies, + Axis + } + [NotMapped] private readonly SemaphoreSlim _processingEvent; public EFClient() @@ -101,6 +109,9 @@ namespace SharedLibraryCore.Database.Models [NotMapped] public string GuidString => NetworkId.ToString("x"); [NotMapped] public ClientState State { get; set; } + + [NotMapped] public TeamType Team { get; set; } + [NotMapped] public string TeamName { get; set; } [NotMapped] // this is kinda dirty, but I need localizable level names @@ -710,6 +721,17 @@ namespace SharedLibraryCore.Database.Models return true; } + public void UpdateTeam(string newTeam) + { + if (string.IsNullOrEmpty(newTeam)) + { + return; + } + + Team = Enum.TryParse(newTeam, true, out TeamType team) ? team : TeamType.Unknown; + TeamName = newTeam; + } + public async Task Lock() { var result = await _processingEvent.WaitAsync(Utilities.DefaultCommandTimeout);