diff --git a/Application/IW4MServer.cs b/Application/IW4MServer.cs index 2c06f07f..aa16ca4d 100644 --- a/Application/IW4MServer.cs +++ b/Application/IW4MServer.cs @@ -703,6 +703,7 @@ namespace IW4MAdmin var updatedClients = polledClients.Except(connectingClients).Except(disconnectingClients); UpdateMap(statusResponse.Item2); + UpdateGametype(statusResponse.Item3); return new List[] { @@ -724,6 +725,14 @@ namespace IW4MAdmin } } + private void UpdateGametype(string gameType) + { + if (!string.IsNullOrEmpty(gameType)) + { + Gametype = gameType; + } + } + private async Task ShutdownInternal() { foreach (var client in GetClientsAsList()) diff --git a/Application/RconParsers/BaseRConParser.cs b/Application/RconParsers/BaseRConParser.cs index 0350763f..a7048c61 100644 --- a/Application/RconParsers/BaseRConParser.cs +++ b/Application/RconParsers/BaseRConParser.cs @@ -52,6 +52,7 @@ namespace IW4MAdmin.Application.RconParsers Configuration.Dvar.AddMapping(ParserRegex.GroupType.RConDvarDomain, 5); Configuration.StatusHeader.Pattern = "num +score +ping +guid +name +lastmsg +address +qport +rate *"; + Configuration.GametypeStatus.Pattern = ""; Configuration.MapStatus.Pattern = @"map: (([a-z]|_|\d)+)"; Configuration.MapStatus.AddMapping(ParserRegex.GroupType.RConStatusMap, 1); @@ -114,7 +115,7 @@ namespace IW4MAdmin.Application.RconParsers }; } - public virtual async Task<(List, string)> GetStatusAsync(IRConConnection connection) + public virtual async Task<(List, string, string)> GetStatusAsync(IRConConnection connection) { string[] response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND_STATUS); #if DEBUG @@ -123,7 +124,7 @@ namespace IW4MAdmin.Application.RconParsers Console.WriteLine(line); } #endif - return (ClientsFromStatus(response), MapFromStatus(response)); + return (ClientsFromStatus(response), MapFromStatus(response), GameTypeFromStatus(response)); } private string MapFromStatus(string[] response) @@ -141,6 +142,26 @@ namespace IW4MAdmin.Application.RconParsers return map; } + private string GameTypeFromStatus(string[] response) + { + if (string.IsNullOrWhiteSpace(Configuration.GametypeStatus.Pattern)) + { + return null; + } + + string gametype = null; + foreach (var line in response) + { + var regex = Regex.Match(line, Configuration.GametypeStatus.Pattern); + if (regex.Success) + { + gametype = regex.Groups[Configuration.GametypeStatus.GroupMapping[ParserRegex.GroupType.RConStatusGametype]].ToString(); + } + } + + return gametype; + } + public async Task SetDvarAsync(IRConConnection connection, string dvarName, object dvarValue) { string dvarString = (dvarValue is string str) diff --git a/Application/RconParsers/DynamicRConParserConfiguration.cs b/Application/RconParsers/DynamicRConParserConfiguration.cs index b043843b..61295f92 100644 --- a/Application/RconParsers/DynamicRConParserConfiguration.cs +++ b/Application/RconParsers/DynamicRConParserConfiguration.cs @@ -14,6 +14,7 @@ namespace IW4MAdmin.Application.RconParsers public CommandPrefix CommandPrefixes { get; set; } public ParserRegex Status { get; set; } public ParserRegex MapStatus { get; set; } + public ParserRegex GametypeStatus { get; set; } public ParserRegex Dvar { get; set; } public ParserRegex StatusHeader { get; set; } public string ServerNotRunningResponse { get; set; } @@ -26,6 +27,7 @@ namespace IW4MAdmin.Application.RconParsers { Status = parserRegexFactory.CreateParserRegex(); MapStatus = parserRegexFactory.CreateParserRegex(); + GametypeStatus = parserRegexFactory.CreateParserRegex(); Dvar = parserRegexFactory.CreateParserRegex(); StatusHeader = parserRegexFactory.CreateParserRegex(); } diff --git a/Plugins/ScriptPlugins/ParserT7.js b/Plugins/ScriptPlugins/ParserT7.js index a379f4a8..af857c88 100644 --- a/Plugins/ScriptPlugins/ParserT7.js +++ b/Plugins/ScriptPlugins/ParserT7.js @@ -3,7 +3,7 @@ var eventParser; var plugin = { author: 'RaidMax', - version: 0.2, + version: 0.3, name: 'Black Ops 3 Parser', isParser: true, @@ -23,6 +23,8 @@ var plugin = { rconParser.Configuration.CommandPrefixes.RConGetDvar = '\xff\xff\xff\xff\x00{0} {1}'; rconParser.Configuration.CommandPrefixes.RConSetDvar = '\xff\xff\xff\xff\x00{0} set {1}'; rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xff\x01'; + rconParser.Configuration.GametypeStatus.Pattern = 'Gametype: (.+)'; + rconParser.Configuration.MapStatus.Pattern = 'Map: (.+)'; rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined; // disables this, because it's useless on T7 rconParser.Configuration.ServerNotRunningResponse = 'this is here to prevent a hiberating server from being detected as not running'; @@ -34,6 +36,7 @@ var plugin = { rconParser.Configuration.DefaultDvarValues.Add('fs_game', ''); rconParser.Configuration.Status.AddMapping(105, 6); // ip address + rconParser.Configuration.GametypeStatus.AddMapping(112, 1); // gametype rconParser.Version = '[local] ship win64 CODBUILD8-764 (3421987) Mon Dec 16 10:44:20 2019 10d27bef'; rconParser.GameName = 8; // BO3 rconParser.CanGenerateLogPath = false; @@ -49,4 +52,4 @@ var plugin = { onTickAsync: function (server) { } -}; \ No newline at end of file +}; diff --git a/SharedLibraryCore/Helpers/ParserRegex.cs b/SharedLibraryCore/Helpers/ParserRegex.cs index 8fa409db..379d19b8 100644 --- a/SharedLibraryCore/Helpers/ParserRegex.cs +++ b/SharedLibraryCore/Helpers/ParserRegex.cs @@ -37,6 +37,7 @@ namespace SharedLibraryCore.Interfaces RConDvarLatchedValue = 109, RConDvarDomain = 110, RConStatusMap = 111, + RConStatusGametype = 112, AdditionalGroup = 200 } diff --git a/SharedLibraryCore/Interfaces/IRConParser.cs b/SharedLibraryCore/Interfaces/IRConParser.cs index 3d1a4dbe..d560a377 100644 --- a/SharedLibraryCore/Interfaces/IRConParser.cs +++ b/SharedLibraryCore/Interfaces/IRConParser.cs @@ -38,8 +38,8 @@ namespace SharedLibraryCore.Interfaces /// get the list of connected clients from status response /// /// RCon connection to use - /// list of clients, and current map - Task<(List, string)> GetStatusAsync(IRConConnection connection); + /// list of clients, current map, and current gametype + Task<(List, string, string)> GetStatusAsync(IRConConnection connection); /// /// stores the RCon configuration diff --git a/SharedLibraryCore/Interfaces/IRConParserConfiguration.cs b/SharedLibraryCore/Interfaces/IRConParserConfiguration.cs index 757bab4c..aee38e28 100644 --- a/SharedLibraryCore/Interfaces/IRConParserConfiguration.cs +++ b/SharedLibraryCore/Interfaces/IRConParserConfiguration.cs @@ -21,6 +21,11 @@ namespace SharedLibraryCore.Interfaces /// ParserRegex MapStatus { get; set; } + /// + /// stores regex info for parsing the gametype line from rcon status response + /// + ParserRegex GametypeStatus { get; set; } + /// /// stores the regex info for parsing get DVAR responses /// diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs index 427a4836..46118dcd 100644 --- a/SharedLibraryCore/Utilities.cs +++ b/SharedLibraryCore/Utilities.cs @@ -786,7 +786,7 @@ namespace SharedLibraryCore return await server.RconParser.ExecuteCommandAsync(server.RemoteConnection, commandName); } - public static Task<(List, string)> GetStatusAsync(this Server server) + public static Task<(List, string, string)> GetStatusAsync(this Server server) { return server.RconParser.GetStatusAsync(server.RemoteConnection); }