diff --git a/Application/EventParsers/BaseEventParser.cs b/Application/EventParsers/BaseEventParser.cs index fdb5cc37a..a786628ea 100644 --- a/Application/EventParsers/BaseEventParser.cs +++ b/Application/EventParsers/BaseEventParser.cs @@ -255,6 +255,7 @@ namespace IW4MAdmin.Application.EventParsers ClientNumber = Convert.ToInt32(match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()), State = EFClient.ClientState.Connecting, }, + Extra = originIdString, RequiredEntity = GameEvent.EventRequiredEntity.None, IsBlocking = true, GameTime = gameTime, diff --git a/Application/IW4MServer.cs b/Application/IW4MServer.cs index 3d44e6e95..1b5f02a62 100644 --- a/Application/IW4MServer.cs +++ b/Application/IW4MServer.cs @@ -816,6 +816,7 @@ namespace IW4MAdmin Origin = client, Owner = this, IsBlocking = true, + Extra = client.GetAdditionalProperty("BotGuid"), Source = GameEvent.EventSource.Status }; diff --git a/Application/RconParsers/BaseRConParser.cs b/Application/RconParsers/BaseRConParser.cs index a7048c61b..d1af19c58 100644 --- a/Application/RconParsers/BaseRConParser.cs +++ b/Application/RconParsers/BaseRConParser.cs @@ -203,10 +203,11 @@ namespace IW4MAdmin.Application.RconParsers long networkId; string name = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConName]].TrimNewLine(); + string networkIdString; try { - string networkIdString = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConNetworkId]]; + networkIdString = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConNetworkId]]; networkId = networkIdString.IsBotGuid() ? name.GenerateGuidFromString() : @@ -234,6 +235,8 @@ namespace IW4MAdmin.Application.RconParsers State = EFClient.ClientState.Connecting }; + client.SetAdditionalProperty("BotGuid", networkIdString); + StatusPlayers.Add(client); } } diff --git a/Plugins/LiveRadar/Controllers/RadarController.cs b/Plugins/LiveRadar/Controllers/RadarController.cs index 17f6e3930..4180ddc5d 100644 --- a/Plugins/LiveRadar/Controllers/RadarController.cs +++ b/Plugins/LiveRadar/Controllers/RadarController.cs @@ -74,14 +74,14 @@ namespace LiveRadar.Web.Controllers [Route("Radar/Update")] public IActionResult Update(string payload) { - var radarUpdate = RadarEvent.Parse(payload); + /*var radarUpdate = RadarEvent.Parse(payload); var client = _manager.GetActiveClients().FirstOrDefault(_client => _client.NetworkId == radarUpdate.Guid); if (client != null) { radarUpdate.Name = client.Name.StripColors(); client.SetAdditionalProperty("LiveRadar", radarUpdate); - } + }*/ return Ok(); } diff --git a/Plugins/LiveRadar/Events/Script.cs b/Plugins/LiveRadar/Events/Script.cs new file mode 100644 index 000000000..649155bde --- /dev/null +++ b/Plugins/LiveRadar/Events/Script.cs @@ -0,0 +1,33 @@ +using SharedLibraryCore; +using SharedLibraryCore.Database.Models; +using SharedLibraryCore.Interfaces; +using System.Collections.Generic; +using EventGeneratorCallback = System.ValueTuple>; + +namespace LiveRadar.Events +{ + public class Script : IRegisterEvent + { + private const string EVENT_LIVERADAR = "LiveRadar"; + private EventGeneratorCallback LiveRadar() + { + return (EVENT_LIVERADAR, EVENT_LIVERADAR, (string eventLine, IEventParserConfiguration config, GameEvent autoEvent) => + { + string[] lineSplit = eventLine.Split(";"); + + autoEvent.Type = GameEvent.EventType.Other; + autoEvent.Subtype = EVENT_LIVERADAR; + autoEvent.Origin = new EFClient() { NetworkId = 0 }; + autoEvent.Extra = lineSplit[1]; // guid + + return autoEvent; + } + ); + } + + public IEnumerable Events => new[] { LiveRadar() }; + } +} diff --git a/Plugins/LiveRadar/Plugin.cs b/Plugins/LiveRadar/Plugin.cs index 8f6e114e7..fbbb39309 100644 --- a/Plugins/LiveRadar/Plugin.cs +++ b/Plugins/LiveRadar/Plugin.cs @@ -3,6 +3,7 @@ using SharedLibraryCore; using SharedLibraryCore.Configuration; using SharedLibraryCore.Interfaces; using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -17,12 +18,14 @@ namespace LiveRadar public string Author => "RaidMax"; private readonly IConfigurationHandler _configurationHandler; + private readonly Dictionary _botGuidLookups; private bool addedPage; private readonly object lockObject = new object(); public Plugin(IConfigurationHandlerFactory configurationHandlerFactory) { _configurationHandler = configurationHandlerFactory.GetConfigurationHandler("LiveRadarConfiguration"); + _botGuidLookups = new Dictionary(); } public Task OnEventAsync(GameEvent E, Server S) @@ -41,28 +44,45 @@ namespace LiveRadar } } - if (E.Type == GameEvent.EventType.Unknown) + if (E.Type == GameEvent.EventType.PreConnect && E.Origin.IsBot) { - if (E.Data?.StartsWith("LiveRadar") ?? false) + string botKey = $"BotGuid_{E.Extra}"; + lock (lockObject) { - try + if (!_botGuidLookups.ContainsKey(botKey)) { - var radarUpdate = RadarEvent.Parse(E.Data); - var client = S.Manager.GetActiveClients().FirstOrDefault(_client => _client.NetworkId == radarUpdate.Guid); + _botGuidLookups.Add(botKey, E.Origin.NetworkId); + } + } + } - if (client != null) - { - radarUpdate.Name = client.Name.StripColors(); - client.SetAdditionalProperty("LiveRadar", radarUpdate); - } + if (E.Type == GameEvent.EventType.Other && E.Subtype == "LiveRadar") + { + try + { + string botKey = $"BotGuid_{E.Extra}"; + long generatedBotGuid; + + lock (lockObject) + { + generatedBotGuid = _botGuidLookups.ContainsKey(botKey) ? _botGuidLookups[botKey] : 0; } - catch (Exception e) + var radarUpdate = RadarEvent.Parse(E.Data, generatedBotGuid); + var client = S.Manager.GetActiveClients().FirstOrDefault(_client => _client.NetworkId == radarUpdate.Guid); + + if (client != null) { - S.Logger.WriteWarning($"Could not parse live radar output: {e.Data}"); - S.Logger.WriteDebug(e.GetExceptionInfo()); + radarUpdate.Name = client.Name.StripColors(); + client.SetAdditionalProperty("LiveRadar", radarUpdate); } } + + catch (Exception e) + { + S.Logger.WriteWarning($"Could not parse live radar output: {e.Data}"); + S.Logger.WriteDebug(e.GetExceptionInfo()); + } } return Task.CompletedTask; diff --git a/Plugins/LiveRadar/RadarEvent.cs b/Plugins/LiveRadar/RadarEvent.cs index ef166be6f..dc2354c03 100644 --- a/Plugins/LiveRadar/RadarEvent.cs +++ b/Plugins/LiveRadar/RadarEvent.cs @@ -1,9 +1,7 @@ using SharedLibraryCore; using SharedLibraryCore.Helpers; using System; -using System.Collections.Generic; using System.Linq; -using System.Text; namespace LiveRadar { @@ -39,13 +37,13 @@ namespace LiveRadar return false; } - public static RadarEvent Parse(string input) + public static RadarEvent Parse(string input, long generatedBotGuid) { var items = input.Split(';').Skip(1).ToList(); var parsedEvent = new RadarEvent() { - Guid = items[0].ConvertGuidToLong(System.Globalization.NumberStyles.HexNumber), + Guid = generatedBotGuid, Location = Vector3.Parse(items[1]), ViewAngles = Vector3.Parse(items[2]).FixIW4Angles(), Team = items[3], diff --git a/Plugins/Stats/Helpers/StatManager.cs b/Plugins/Stats/Helpers/StatManager.cs index da9b91c38..bdb588cee 100644 --- a/Plugins/Stats/Helpers/StatManager.cs +++ b/Plugins/Stats/Helpers/StatManager.cs @@ -1232,6 +1232,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers return 886229536; } + // todo: this is not stable and will need to be migrated again... long id = HashCode.Combine(server.IP, server.Port); id = id < 0 ? Math.Abs(id) : id; long? serverId; diff --git a/SharedLibraryCore/Dtos/Meta/Responses/UpdatedAliasResponse.cs b/SharedLibraryCore/Dtos/Meta/Responses/UpdatedAliasResponse.cs index 58772627f..d3460d2a6 100644 --- a/SharedLibraryCore/Dtos/Meta/Responses/UpdatedAliasResponse.cs +++ b/SharedLibraryCore/Dtos/Meta/Responses/UpdatedAliasResponse.cs @@ -1,6 +1,4 @@ -using System; - -namespace SharedLibraryCore.Dtos.Meta.Responses +namespace SharedLibraryCore.Dtos.Meta.Responses { public class UpdatedAliasResponse : BaseMetaResponse { @@ -17,6 +15,6 @@ namespace SharedLibraryCore.Dtos.Meta.Responses return false; } - public override int GetHashCode() => HashCode.Combine(Name.StripColors(), IPAddress); + public override int GetHashCode() => $"{Name.StripColors()}{IPAddress}".GetStableHashCode(); } } diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs index 948d3e5a9..827589c18 100644 --- a/SharedLibraryCore/Utilities.cs +++ b/SharedLibraryCore/Utilities.cs @@ -369,7 +369,27 @@ namespace SharedLibraryCore /// /// value string /// - public static long GenerateGuidFromString(this string value) => string.IsNullOrEmpty(value) ? -1 : HashCode.Combine(value.StripColors()); + public static long GenerateGuidFromString(this string value) => string.IsNullOrEmpty(value) ? -1 : GetStableHashCode(value.StripColors()); + + /// https://stackoverflow.com/questions/36845430/persistent-hashcode-for-strings + public static int GetStableHashCode(this string str) + { + unchecked + { + int hash1 = 5381; + int hash2 = hash1; + + for (int i = 0; i < str.Length && str[i] != '\0'; i += 2) + { + hash1 = ((hash1 << 5) + hash1) ^ str[i]; + if (i == str.Length - 1 || str[i + 1] == '\0') + break; + hash2 = ((hash2 << 5) + hash2) ^ str[i + 1]; + } + + return hash1 + (hash2 * 1566083941); + } + } public static int? ConvertToIP(this string str) { @@ -956,7 +976,7 @@ namespace SharedLibraryCore /// /// wrapper method for humanizee that uses current current culture /// - public static string HumanizeForCurrentCulture(this TimeSpan timeSpan, int precision = 1, TimeUnit maxUnit = TimeUnit.Week, + public static string HumanizeForCurrentCulture(this TimeSpan timeSpan, int precision = 1, TimeUnit maxUnit = TimeUnit.Week, TimeUnit minUnit = TimeUnit.Millisecond, string collectionSeparator = ", ", bool toWords = false) { return timeSpan.Humanize(precision, CurrentLocalization.Culture, maxUnit, minUnit, collectionSeparator, toWords);