diff --git a/Application/DefaultSettings.json b/Application/DefaultSettings.json index a454bca99..fcbab4931 100644 --- a/Application/DefaultSettings.json +++ b/Application/DefaultSettings.json @@ -1251,6 +1251,10 @@ "Alias": "Call of the Dead", "Name": "zombie_coast" }, + { + "Alias": "Shangri-La", + "Name": "zombie_temple" + }, { "Alias": "Moon", "Name": "zombie_moon" diff --git a/Application/Main.cs b/Application/Main.cs index 41eb9901c..2edb79a20 100644 --- a/Application/Main.cs +++ b/Application/Main.cs @@ -432,7 +432,12 @@ namespace IW4MAdmin.Application appConfigHandler.BuildAsync().GetAwaiter().GetResult(); var commandConfigHandler = new BaseConfigurationHandler("CommandConfiguration"); commandConfigHandler.BuildAsync().GetAwaiter().GetResult(); - + + if (appConfigHandler.Configuration()?.MasterUrl == new Uri("http://api.raidmax.org:5000")) + { + appConfigHandler.Configuration().MasterUrl = new ApplicationConfiguration().MasterUrl; + } + var appConfig = appConfigHandler.Configuration(); var masterUri = Utilities.IsDevelopment ? new Uri("http://127.0.0.1:8080") diff --git a/Application/RConParsers/BaseRConParser.cs b/Application/RConParsers/BaseRConParser.cs index a918c552f..cf773dd19 100644 --- a/Application/RConParsers/BaseRConParser.cs +++ b/Application/RConParsers/BaseRConParser.cs @@ -194,10 +194,14 @@ namespace IW4MAdmin.Application.RConParsers foreach (var line in response) { var regex = Regex.Match(line, parserRegex.Pattern); - if (regex.Success && parserRegex.GroupMapping.ContainsKey(groupType)) + + if (!regex.Success || !parserRegex.GroupMapping.ContainsKey(groupType)) { - value = regex.Groups[parserRegex.GroupMapping[groupType]].ToString(); + continue; } + + value = regex.Groups[parserRegex.GroupMapping[groupType]].ToString(); + break; } if (value == null) diff --git a/Data/Models/Reference.cs b/Data/Models/Reference.cs index 095b71b29..cfa68de15 100644 --- a/Data/Models/Reference.cs +++ b/Data/Models/Reference.cs @@ -16,7 +16,8 @@ T7 = 8, SHG1 = 9, CSGO = 10, - H1 = 11 + H1 = 11, + LFD2 = 12, } public enum ConnectionType diff --git a/GameFiles/GameInterface/_integration_t5.gsc b/GameFiles/GameInterface/_integration_t5.gsc index 962da312e..fa11f1c5a 100644 --- a/GameFiles/GameInterface/_integration_t5.gsc +++ b/GameFiles/GameInterface/_integration_t5.gsc @@ -88,7 +88,7 @@ IsBotWrapper( client ) GetXuidWrapper() { - return self GetXUID(); + return self GetGuid(); } ////////////////////////////////// diff --git a/IW4MAdmin.sln b/IW4MAdmin.sln index e46ad4273..fd366adbc 100644 --- a/IW4MAdmin.sln +++ b/IW4MAdmin.sln @@ -53,6 +53,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ScriptPlugins", "ScriptPlug Plugins\ScriptPlugins\ParserPlutoniumT5.js = Plugins\ScriptPlugins\ParserPlutoniumT5.js Plugins\ScriptPlugins\ServerBanner.js = Plugins\ScriptPlugins\ServerBanner.js Plugins\ScriptPlugins\ParserBOIII.js = Plugins\ScriptPlugins\ParserBOIII.js + Plugins\ScriptPlugins\ParserLFD2SM.js = Plugins\ScriptPlugins\ParserLFD2SM.js EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutomessageFeed", "Plugins\AutomessageFeed\AutomessageFeed.csproj", "{F5815359-CFC7-44B4-9A3B-C04BACAD5836}" diff --git a/Plugins/ScriptPlugins/ParserCSGO.js b/Plugins/ScriptPlugins/ParserCSGO.js index eb63d824a..5573cfe94 100644 --- a/Plugins/ScriptPlugins/ParserCSGO.js +++ b/Plugins/ScriptPlugins/ParserCSGO.js @@ -22,10 +22,10 @@ const plugin = { rconParser.Configuration.MapStatus.AddMapping(111, 1); rconParser.Configuration.HostnameStatus.Pattern = '^hostname: +(.+)$'; - rconParser.Configuration.MapStatus.AddMapping(113, 1); + rconParser.Configuration.HostnameStatus.AddMapping(113, 1); rconParser.Configuration.MaxPlayersStatus.Pattern = '^players *: +\\d+ humans, \\d+ bots \\((\\d+).+'; - rconParser.Configuration.MapStatus.AddMapping(114, 1); + rconParser.Configuration.MaxPlayersStatus.AddMapping(114, 1); rconParser.Configuration.Dvar.Pattern = '^"(.+)" = "(.+)" (?:\\( def. "(.*)" \\))?(?: |\\w)+- (.+)$'; rconParser.Configuration.Dvar.AddMapping(106, 1); diff --git a/Plugins/ScriptPlugins/ParserCSGOSM.js b/Plugins/ScriptPlugins/ParserCSGOSM.js index 950d07b72..67f95df44 100644 --- a/Plugins/ScriptPlugins/ParserCSGOSM.js +++ b/Plugins/ScriptPlugins/ParserCSGOSM.js @@ -3,7 +3,7 @@ let eventParser; const plugin = { author: 'RaidMax', - version: 0.6, + version: 0.7, name: 'CS:GO (SourceMod) Parser', engine: 'Source', isParser: true, @@ -22,10 +22,10 @@ const plugin = { rconParser.Configuration.MapStatus.AddMapping(111, 1); rconParser.Configuration.HostnameStatus.Pattern = '^hostname: +(.+)$'; - rconParser.Configuration.MapStatus.AddMapping(113, 1); + rconParser.Configuration.HostnameStatus.AddMapping(113, 1); rconParser.Configuration.MaxPlayersStatus.Pattern = '^players *: +\\d+ humans, \\d+ bots \\((\\d+).+'; - rconParser.Configuration.MapStatus.AddMapping(114, 1); + rconParser.Configuration.MaxPlayersStatus.AddMapping(114, 1); rconParser.Configuration.Dvar.Pattern = '^"(.+)" = "(.+)" (?:\\( def. "(.*)" \\))?(?: |\\w)+- (.+)$'; rconParser.Configuration.Dvar.AddMapping(106, 1); diff --git a/Plugins/ScriptPlugins/ParserLFD2SM.js b/Plugins/ScriptPlugins/ParserLFD2SM.js new file mode 100644 index 000000000..713caef31 --- /dev/null +++ b/Plugins/ScriptPlugins/ParserLFD2SM.js @@ -0,0 +1,135 @@ +let rconParser; +let eventParser; + +const plugin = { + author: 'RaidMax', + version: 0.1, + name: 'LFD2 (SourceMod) Parser', + engine: 'Source', + isParser: true, + + onEventAsync: function (gameEvent, server) { + }, + + onLoadAsync: function (manager) { + rconParser = manager.GenerateDynamicRConParser(this.name); + eventParser = manager.GenerateDynamicEventParser(this.name); + rconParser.RConEngine = this.engine; + + rconParser.Configuration.StatusHeader.Pattern = '# userid name uniqueid connected ping loss state rate adr'; + + rconParser.Configuration.MapStatus.Pattern = '^map *: +(.+)$'; + rconParser.Configuration.MapStatus.AddMapping(111, 1); + + rconParser.Configuration.HostnameStatus.Pattern = '^hostname: +(.+)$'; + rconParser.Configuration.HostnameStatus.AddMapping(113, 1); + + rconParser.Configuration.MaxPlayersStatus.Pattern = '^players *: +\\d+ humans, \\d+ bots \\((\\d+).+'; + rconParser.Configuration.MaxPlayersStatus.AddMapping(114, 1); + + rconParser.Configuration.Dvar.Pattern = '^\\"(.+)\\" (?:=|is) \\"(.+)\\"(?: (?:\\( def. \\"(.*)\\" \\)))?$'; + rconParser.Configuration.Dvar.AddMapping(106, 1); + rconParser.Configuration.Dvar.AddMapping(107, 2); + rconParser.Configuration.Dvar.AddMapping(108, 3); + rconParser.Configuration.Dvar.AddMapping(109, 3); + + rconParser.Configuration.Status.Pattern = '^#\\s*(\\d+) (\\d+) "(.+)" (\\S+) +(\\d+:\\d+(?::\\d+)?) (\\d+) (\\S+) (\\S+) (\\d+) (\\d+\\.\\d+\\.\\d+\\.\\d+:\\d+)$'; + rconParser.Configuration.Status.AddMapping(100, 2); + rconParser.Configuration.Status.AddMapping(101, -1); + rconParser.Configuration.Status.AddMapping(102, 6); + rconParser.Configuration.Status.AddMapping(103, 4) + rconParser.Configuration.Status.AddMapping(104, 3); + rconParser.Configuration.Status.AddMapping(105, 10); + rconParser.Configuration.Status.AddMapping(200, 1); + + rconParser.Configuration.DefaultDvarValues.Add('sv_running', '1'); + rconParser.Configuration.DefaultDvarValues.Add('bugfix_no_version', this.engine); + rconParser.Configuration.DefaultDvarValues.Add('fs_basepath', ''); + rconParser.Configuration.DefaultDvarValues.Add('fs_basegame', ''); + rconParser.Configuration.DefaultDvarValues.Add('fs_homepath', ''); + rconParser.Configuration.DefaultDvarValues.Add('g_log', ''); + rconParser.Configuration.DefaultDvarValues.Add('net_ip', 'localhost'); + rconParser.Configuration.DefaultDvarValues.Add('g_gametype', ''); + rconParser.Configuration.DefaultDvarValues.Add('fs_game', ''); + + rconParser.Configuration.OverrideDvarNameMapping.Add('sv_hostname', 'hostname'); + rconParser.Configuration.OverrideDvarNameMapping.Add('mapname', 'host_map'); + rconParser.Configuration.OverrideDvarNameMapping.Add('sv_maxclients', 'maxplayers'); + rconParser.Configuration.OverrideDvarNameMapping.Add('g_password', 'sv_password'); + rconParser.Configuration.OverrideDvarNameMapping.Add('version', 'bugfix_no_version'); + + rconParser.Configuration.ColorCodeMapping.Clear(); + rconParser.Configuration.ColorCodeMapping.Add('White', '\x01'); + rconParser.Configuration.ColorCodeMapping.Add('Red', '\x07'); + rconParser.Configuration.ColorCodeMapping.Add('LightRed', '\x0F'); + rconParser.Configuration.ColorCodeMapping.Add('DarkRed', '\x02'); + rconParser.Configuration.ColorCodeMapping.Add('Blue', '\x0B'); + rconParser.Configuration.ColorCodeMapping.Add('DarkBlue', '\x0C'); + rconParser.Configuration.ColorCodeMapping.Add('Purple', '\x03'); + rconParser.Configuration.ColorCodeMapping.Add('Orchid', '\x0E'); + rconParser.Configuration.ColorCodeMapping.Add('Yellow', '\x09'); + rconParser.Configuration.ColorCodeMapping.Add('Gold', '\x10'); + rconParser.Configuration.ColorCodeMapping.Add('LightGreen', '\x05'); + rconParser.Configuration.ColorCodeMapping.Add('Green', '\x04'); + rconParser.Configuration.ColorCodeMapping.Add('Lime', '\x06'); + rconParser.Configuration.ColorCodeMapping.Add('Grey', '\x08'); + rconParser.Configuration.ColorCodeMapping.Add('Grey2', '\x0D'); + // only adding there here for the default accent color + rconParser.Configuration.ColorCodeMapping.Add('Cyan', '\x0B'); + + rconParser.Configuration.NoticeLineSeparator = '. '; + rconParser.Configuration.DefaultRConPort = 27015; + rconParser.CanGenerateLogPath = false; + + rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined; + rconParser.Configuration.CommandPrefixes.Kick = 'sm_kick #{0} {1}'; + rconParser.Configuration.CommandPrefixes.Ban = 'sm_kick #{0} {1}'; + rconParser.Configuration.CommandPrefixes.TempBan = 'sm_kick #{0} {1}'; + rconParser.Configuration.CommandPrefixes.Say = 'sm_say {0}'; + rconParser.Configuration.CommandPrefixes.Tell = 'sm_psay #{0} "{1}"'; + + eventParser.Configuration.Say.Pattern = '^"(.+)<(\\d+)><(.+)><(.*?)>" (?:say|say_team) "(.*)"$'; + eventParser.Configuration.Say.AddMapping(5, 1); + eventParser.Configuration.Say.AddMapping(3, 2); + eventParser.Configuration.Say.AddMapping(1, 3); + eventParser.Configuration.Say.AddMapping(7, 4); + eventParser.Configuration.Say.AddMapping(13, 5); + + eventParser.Configuration.Kill.Pattern = '^"(.+)<(\\d+)><(.+)><(.*)>" \\[-?\\d+ -?\\d+ -?\\d+\\] killed "(.+)<(\\d+)><(.+)><(.*)>" \\[-?\\d+ -?\\d+ -?\\d+\\] with "(\\S*)" *(?:\\((\\w+)((?: ).+)?\\))?$'; + eventParser.Configuration.Kill.AddMapping(5, 1); + eventParser.Configuration.Kill.AddMapping(3, 2); + eventParser.Configuration.Kill.AddMapping(1, 3); + eventParser.Configuration.Kill.AddMapping(7, 4); + eventParser.Configuration.Kill.AddMapping(6, 5); + eventParser.Configuration.Kill.AddMapping(4, 6); + eventParser.Configuration.Kill.AddMapping(2, 7); + eventParser.Configuration.Kill.AddMapping(8, 8); + eventParser.Configuration.Kill.AddMapping(9, 9); + eventParser.Configuration.Kill.AddMapping(12, 10); + + eventParser.Configuration.MapEnd.Pattern = '^World triggered "Match_Start" on "(.+)"$'; + + eventParser.Configuration.JoinTeam.Pattern = '^"(.+)<(\\d+)><(.*)>" switched from team <(.+)> to <(.+)>$'; + eventParser.Configuration.JoinTeam.AddMapping(5, 1); + eventParser.Configuration.JoinTeam.AddMapping(3, 2); + eventParser.Configuration.JoinTeam.AddMapping(1, 3); + eventParser.Configuration.JoinTeam.AddMapping(7, 5); + + eventParser.Configuration.TeamMapping.Add('CT', 2); + eventParser.Configuration.TeamMapping.Add('TERRORIST', 3); + + eventParser.Configuration.Time.Pattern = '^L [01]\\d/[0-3]\\d/\\d+ - [0-2]\\d:[0-5]\\d:[0-5]\\d:'; + + rconParser.Version = 'LFD2SM'; + rconParser.GameName = 10; // LFD2 + eventParser.Version = 'LFD2SM'; + eventParser.GameName = 10; // LFD2 + eventParser.URLProtocolFormat = 'steam://connect/{{ip}}:{{port}}'; + }, + + onUnloadAsync: function () { + }, + + onTickAsync: function (server) { + } +}; diff --git a/Plugins/Stats/Dtos/ChatSearchQuery.cs b/Plugins/Stats/Dtos/ChatSearchQuery.cs index f58f1145f..443389079 100644 --- a/Plugins/Stats/Dtos/ChatSearchQuery.cs +++ b/Plugins/Stats/Dtos/ChatSearchQuery.cs @@ -28,18 +28,19 @@ namespace Stats.Dtos /// /// The time associated with SentAfter date /// - public string SentAfterTime { get; set; } = "00:00"; + public string SentAfterTime { get; set; } - public DateTime? SentAfterDateTime => SentAfter?.Add(TimeSpan.Parse(SentAfterTime)); + public DateTime? SentAfterDateTime => SentAfter?.Add(string.IsNullOrEmpty(SentAfterTime) ? TimeSpan.Zero : TimeSpan.Parse(SentAfterTime)); /// /// only look for messages sent before this date0 /// public DateTime SentBefore { get; set; } = DateTime.UtcNow.Date; - public string SentBeforeTime { get; set; } = DateTime.UtcNow.ToString("HH:mm"); + public string SentBeforeTime { get; set; } - public DateTime? SentBeforeDateTime => SentBefore.Add(TimeSpan.Parse(SentBeforeTime)); + public DateTime? SentBeforeDateTime => + SentBefore.Add(string.IsNullOrEmpty(SentBeforeTime) ? TimeSpan.Zero : TimeSpan.Parse(SentBeforeTime)); public bool IsExactMatch { get; set; } diff --git a/Plugins/Stats/Plugin.cs b/Plugins/Stats/Plugin.cs index ee8ccc7da..fabc6da29 100644 --- a/Plugins/Stats/Plugin.cs +++ b/Plugins/Stats/Plugin.cs @@ -469,6 +469,8 @@ public class Plugin : IPluginV2 ClientId = request.ClientId, Before = request.Before, SentBefore = request.Before ?? DateTime.UtcNow, + SentAfter = request.After, + After = request.After, Count = request.Count, IsProfileMeta = true }; diff --git a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs index da052c9d8..4e5c9c169 100644 --- a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs +++ b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs @@ -206,7 +206,7 @@ namespace SharedLibraryCore.Configuration : ManualWebfrontUrl; [ConfigurationIgnore] public bool IgnoreServerConnectionLost { get; set; } - [ConfigurationIgnore] public Uri MasterUrl { get; set; } = new("http://api.raidmax.org:5000"); + [ConfigurationIgnore] public Uri MasterUrl { get; set; } = new("https://master.iw4.zip"); public IBaseConfiguration Generate() { diff --git a/SharedLibraryCore/Configuration/Validation/ApplicationConfigurationValidator.cs b/SharedLibraryCore/Configuration/Validation/ApplicationConfigurationValidator.cs index 4841d373d..78864fac3 100644 --- a/SharedLibraryCore/Configuration/Validation/ApplicationConfigurationValidator.cs +++ b/SharedLibraryCore/Configuration/Validation/ApplicationConfigurationValidator.cs @@ -67,7 +67,7 @@ namespace SharedLibraryCore.Configuration.Validation RuleFor(_app => _app.MasterUrl) .NotNull() - .Must(_url => _url != null && _url.Scheme == Uri.UriSchemeHttp); + .Must(_url => _url != null && (_url.Scheme == Uri.UriSchemeHttp || _url.Scheme == Uri.UriSchemeHttps)); RuleFor(_app => _app.CommandPrefix) .NotEmpty(); @@ -80,4 +80,4 @@ namespace SharedLibraryCore.Configuration.Validation .SetValidator(new ServerConfigurationValidator()); } } -} \ No newline at end of file +} diff --git a/SharedLibraryCore/Server.cs b/SharedLibraryCore/Server.cs index d78182813..0abf1be11 100644 --- a/SharedLibraryCore/Server.cs +++ b/SharedLibraryCore/Server.cs @@ -35,7 +35,8 @@ namespace SharedLibraryCore T7 = 8, SHG1 = 9, CSGO = 10, - H1 = 11 + H1 = 11, + LFD2 = 12 } // only here for performance