From 01b5a4945f416fae9ce89f0bd31c662f35da855f Mon Sep 17 00:00:00 2001 From: glax Date: Mon, 15 Jan 2024 22:37:00 +0100 Subject: [PATCH] Add Events --- CS2EventArgs.cs | 6 ++ CS2EventGenerator.cs | 107 ++++++++++++++++++++++++ CS2GSI.cs | 191 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 304 insertions(+) create mode 100644 CS2EventArgs.cs create mode 100644 CS2EventGenerator.cs create mode 100644 CS2GSI.cs diff --git a/CS2EventArgs.cs b/CS2EventArgs.cs new file mode 100644 index 0000000..0fc497d --- /dev/null +++ b/CS2EventArgs.cs @@ -0,0 +1,6 @@ +namespace CS2GSI; + +public class CS2EventArgs : EventArgs +{ + +} \ No newline at end of file diff --git a/CS2EventGenerator.cs b/CS2EventGenerator.cs new file mode 100644 index 0000000..4616e0d --- /dev/null +++ b/CS2EventGenerator.cs @@ -0,0 +1,107 @@ +using CS2GSI.GameState; +using CS2Event = CS2GSI.CS2GSI.CS2Event; + +namespace CS2GSI; + +internal static class CS2EventGenerator +{ + internal static List> GenerateEvents(CS2GameState previousPlayerState, CS2GameState newGameState, CS2GameState lastGameState) + { + List> events = new(); + events.AddRange(GeneratePlayerEvents(previousPlayerState, newGameState)); + events.AddRange(GenerateMapEvents(previousPlayerState, newGameState, lastGameState)); + + if(lastGameState.Player?.SteamId != newGameState.Player?.SteamId) + events.Add(new ValueTuple(CS2Event.OnPlayerChange, new CS2EventArgs())); + + if(events.Count > 0) + events.Add(new ValueTuple(CS2Event.AnyEvent, new CS2EventArgs())); + return events; + } + + private static List> GenerateMapEvents(CS2GameState previousPlayerState, CS2GameState newGameState, CS2GameState lastGameState) + { + List> events = new(); + + if (newGameState.Player?.Team == previousPlayerState.Player?.Team && lastGameState.Player?.Team == previousPlayerState.Player?.Team) + { + if(newGameState.Round?.Phase == Round.RoundPhase.Live && lastGameState.Round?.Phase != Round.RoundPhase.Live) + events.Add(new ValueTuple(CS2Event.OnRoundStart, new CS2EventArgs())); + + if(newGameState.Round?.Phase == Round.RoundPhase.Over && lastGameState.Round?.Phase == Round.RoundPhase.Live) + events.Add(new ValueTuple(CS2Event.OnRoundOver, new CS2EventArgs())); + } + + if(newGameState.Map?.Phase == Map.MapPhase.Live && lastGameState.Map?.Phase != Map.MapPhase.Live) + events.Add(new ValueTuple(CS2Event.OnMatchStart, new CS2EventArgs())); + + if(newGameState.Map?.Phase == Map.MapPhase.GameOver && lastGameState.Map?.Phase != Map.MapPhase.GameOver) + events.Add(new ValueTuple(CS2Event.OnMatchOver, new CS2EventArgs())); + + if(newGameState.Map?.Phase == Map.MapPhase.Intermission && lastGameState.Map?.Phase != Map.MapPhase.Intermission) + events.Add(new ValueTuple(CS2Event.OnHalfTime, new CS2EventArgs())); + + if(newGameState.Round?.Phase == Round.RoundPhase.Freezetime && lastGameState.Round?.Phase != Round.RoundPhase.Freezetime) + events.Add(new ValueTuple(CS2Event.OnFreezeTime, new CS2EventArgs())); + + if(newGameState.Round?.Bomb == Round.BombStatus.Planted && lastGameState.Round?.Bomb != Round.BombStatus.Planted) + events.Add(new ValueTuple(CS2Event.OnBombPlanted, new CS2EventArgs())); + + if(newGameState.Round?.Bomb == Round.BombStatus.Defused && lastGameState.Round?.Bomb != Round.BombStatus.Defused) + events.Add(new ValueTuple(CS2Event.OnBombDefused, new CS2EventArgs())); + + if(newGameState.Round?.Bomb == Round.BombStatus.Exploded && lastGameState.Round?.Bomb != Round.BombStatus.Exploded) + events.Add(new ValueTuple(CS2Event.OnBombExploded, new CS2EventArgs())); + + return events; + } + + private static List> GeneratePlayerEvents(CS2GameState previousPlayerState, CS2GameState newGameState) + { + List> events = new(); + if (newGameState.Player?.SteamId != newGameState.ProviderSteamId || previousPlayerState.Player?.SteamId != newGameState.Player?.SteamId) + return events; + + if(newGameState.Player?.MatchStats?.Kills > previousPlayerState.Player?.MatchStats?.Kills && newGameState.Player is { MatchStats: not null}) + events.Add(new ValueTuple(CS2Event.OnKill, new CS2EventArgs())); + + if(newGameState.Player?.State?.RoundHs > previousPlayerState.Player?.State?.RoundHs && newGameState.Player is { State: not null}) + events.Add(new ValueTuple(CS2Event.OnHeadshot, new CS2EventArgs())); + + if(newGameState.Player?.MatchStats?.Deaths > previousPlayerState.Player?.MatchStats?.Deaths && newGameState.Player is { MatchStats: not null}) + events.Add(new ValueTuple(CS2Event.OnDeath, new CS2EventArgs())); + + if(newGameState.Player?.State?.Flashed > 0 && newGameState.Player is { State: not null}) + events.Add(new ValueTuple(CS2Event.OnFlashed, new CS2EventArgs())); + + if(newGameState.Player?.State?.Burning > 0 && newGameState.Player is { State: not null}) + events.Add(new ValueTuple(CS2Event.OnBurning, new CS2EventArgs())); + + if(newGameState.Player?.State?.Smoked > 0 && newGameState.Player is { State: not null}) + events.Add(new ValueTuple(CS2Event.OnSmoked, new CS2EventArgs())); + + if(newGameState.Player?.State?.Health < previousPlayerState.Player?.State?.Health && newGameState.Player is { State: not null}) + events.Add(new ValueTuple(CS2Event.OnDamageTaken, new CS2EventArgs())); + + if(newGameState.Player?.State?.Health != previousPlayerState.Player?.State?.Health && newGameState.Player is { State: not null}) + events.Add(new ValueTuple(CS2Event.OnHealthChange, new CS2EventArgs())); + + if(newGameState.Player?.State?.Money != previousPlayerState.Player?.State?.Money && newGameState.Player is { State: not null}) + events.Add(new ValueTuple(CS2Event.OnMoneyChange, new CS2EventArgs())); + + if(newGameState.Player?.State?.Armor != previousPlayerState.Player?.State?.Armor && newGameState.Player is { State: not null}) + events.Add(new ValueTuple(CS2Event.OnArmorChange, new CS2EventArgs())); + + if(newGameState.Player?.State?.Helmet != previousPlayerState.Player?.State?.Helmet && newGameState.Player is { State: not null}) + events.Add(new ValueTuple(CS2Event.OnHelmetChange, new CS2EventArgs())); + + if(newGameState.Player?.State?.EquipmentValue != previousPlayerState.Player?.State?.EquipmentValue && newGameState.Player is { State: not null}) + events.Add(new ValueTuple(CS2Event.OnEquipmentValueChange, new CS2EventArgs())); + + if(newGameState.Player?.Team != previousPlayerState.Player?.Team && newGameState.Player is not null) + events.Add(new ValueTuple(CS2Event.OnTeamChange, new CS2EventArgs())); + + + return events; + } +} \ No newline at end of file diff --git a/CS2GSI.cs b/CS2GSI.cs new file mode 100644 index 0000000..50ab5b9 --- /dev/null +++ b/CS2GSI.cs @@ -0,0 +1,191 @@ +using CS2GSI.GameState; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json.Linq; + +namespace CS2GSI; + +public class CS2GSI +{ + private GSIServer _gsiServer; + private List _allGameStates = new(); + private CS2GameState? _lastLocalGameState = null; + private ILogger? logger; + + public CS2GSI(ILogger? logger = null) + { + this.logger = logger; + this.logger?.Log(LogLevel.Information, "Installing GSI-Configfile..."); + try + { + GsiConfigInstaller.InstallGsi(); + } + catch (Exception e) + { + this.logger?.Log(LogLevel.Error, e.StackTrace); + this.logger?.Log(LogLevel.Critical, "Could not install GSI-Configfile. Exiting."); + return; + } + this._gsiServer = new GSIServer(3000); + this._gsiServer.OnMessage += messageJson => + { + JObject jsonObject = JObject.Parse(messageJson); + CS2GameState newState = CS2GameState.ParseFromJObject(jsonObject); + this.logger?.Log(LogLevel.Debug, $"Received State:\n{newState.ToString()}"); + this._lastLocalGameState = newState.UpdateGameStateForLocal(_lastLocalGameState); + this.logger?.Log(LogLevel.Debug, $"Updated Local State:\n{_lastLocalGameState.ToString()}"); + + if (_lastLocalGameState is not null) + { + List> generatedEvents = CS2EventGenerator.GenerateEvents(_lastLocalGameState.Value, newState, _allGameStates.Last()); + this.logger?.Log(LogLevel.Information, $"Generated {generatedEvents.Count} events."); + if(generatedEvents.Count > 0) + this.logger?.Log(LogLevel.Debug, $"Events:\n\t{string.Join("\n\t", generatedEvents)}"); + InvokeEvents(generatedEvents); + } + _allGameStates.Add(newState); + }; + } + + private void InvokeEvents(List> cs2Events) + { + foreach(ValueTuple cs2Event in cs2Events) + InvokeEvent(cs2Event); + } + + private void InvokeEvent(ValueTuple cs2Event) + { + switch (cs2Event.Item1) + { + case CS2Event.OnKill: + OnKill?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnHeadshot: + OnHeadshot?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnDeath: + OnDeath?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnFlashed: + OnFlashed?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnBurning: + OnBurning?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnSmoked: + OnSmoked?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnRoundStart: + OnRoundStart?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnRoundOver: + OnRoundOver?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnDamageTaken: + OnDamageTaken?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnMatchStart: + OnMatchStart?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnMatchOver: + OnMatchOver?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnMoneyChange: + OnMoneyChange?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnHealthChange: + OnHealthChange?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnArmorChange: + OnArmorChange?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnHelmetChange: + OnHelmetChange?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnEquipmentValueChange: + OnEquipmentValueChange?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnTeamChange: + OnTeamChange?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnPlayerChange: + OnPlayerChange?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnFreezeTime: + OnFreezeTime?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnHalfTime: + OnHalfTime?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnBombDefused: + OnBombDefused?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnBombExploded: + OnBombExploded?.Invoke(cs2Event.Item2); + break; + case CS2Event.OnBombPlanted: + OnBombPlanted?.Invoke(cs2Event.Item2); + break; + case CS2Event.AnyEvent: + AnyEvent?.Invoke(cs2Event.Item2); + break; + default: + this.logger?.Log(LogLevel.Error, $"Unknown Event {cs2Event}"); + return; + } + } + + internal enum CS2Event { + OnKill, + OnHeadshot, + OnDeath, + OnFlashed, + OnBurning, + OnSmoked, + OnRoundStart, + OnRoundOver, + OnDamageTaken, + OnMatchStart, + OnMatchOver, + OnMoneyChange, + OnHealthChange, + OnArmorChange, + OnHelmetChange, + OnEquipmentValueChange, + OnTeamChange, + OnPlayerChange, + OnHalfTime, + OnFreezeTime, + OnBombPlanted, + OnBombDefused, + OnBombExploded, + AnyEvent + } + + public delegate void CS2EventHandler(CS2EventArgs eventArgs); + + public event CS2EventHandler? OnKill, + OnHeadshot, + OnDeath, + OnFlashed, + OnBurning, + OnSmoked, + OnRoundStart, + OnRoundOver, + OnDamageTaken, + OnMatchStart, + OnMatchOver, + OnMoneyChange, + OnHealthChange, + OnArmorChange, + OnHelmetChange, + OnEquipmentValueChange, + OnTeamChange, + OnPlayerChange, + OnHalfTime, + OnFreezeTime, + OnBombPlanted, + OnBombDefused, + OnBombExploded, + AnyEvent; + +} \ No newline at end of file