diff --git a/CS2GSI.csproj b/CS2GSI.csproj
index c0c3371..49fa879 100644
--- a/CS2GSI.csproj
+++ b/CS2GSI.csproj
@@ -21,4 +21,8 @@
+
+
+
+
diff --git a/CS2GSIJsonParser.cs b/CS2GSIJsonParser.cs
new file mode 100644
index 0000000..9ad24c4
--- /dev/null
+++ b/CS2GSIJsonParser.cs
@@ -0,0 +1,87 @@
+using CS2GSI.GameState;
+using Newtonsoft.Json.Linq;
+
+namespace CS2GSI;
+
+internal static class CS2GSIJsonParser
+{
+ internal static CS2GameState ParseGameStateFromJson(string jsonString)
+ {
+ JObject jsonObject = JObject.Parse(jsonString);
+ return new CS2GameState()
+ {
+ Timestamp = jsonObject.SelectToken("provider.timestamp")!.Value(),
+ Map = ParseMapFromJObject(jsonObject),
+ Player = ParsePlayerFromJObject(jsonObject)
+ };
+ }
+
+ private static Map? ParseMapFromJObject(JObject jsonObject)
+ {
+ return jsonObject.SelectToken("map") is { } mapToken
+ ? new Map()
+ {
+ Mode = jsonObject.SelectToken("map.mode")!.Value()!,
+ Name = jsonObject.SelectToken("map.name")!.Value()!,
+ Phase = jsonObject.SelectToken("map.phase")!.Value()!,
+ Round = jsonObject.SelectToken("map.round")!.Value(),
+ NumMatchesToWinSeries = jsonObject.SelectToken("map.num_matches_to_win_series")!.Value(),
+ TeamCT = ParseTeamFromJObject(jsonObject, "ct"),
+ TeamT = ParseTeamFromJObject(jsonObject, "t")
+ }
+ : null;
+ }
+
+ private static Team ParseTeamFromJObject(JObject jsonObject, string team)
+ {
+ return new Team()
+ {
+ Score = jsonObject.SelectToken($"map.team_{team}.score")!.Value(),
+ ConsecutiveRoundLosses = jsonObject.SelectToken($"map.team_{team}.consecutive_round_losses")!.Value(),
+ TimeoutsRemaining = jsonObject.SelectToken($"map.team_{team}.timeouts_remaining")!.Value(),
+ MatchesWonThisSeries = jsonObject.SelectToken($"map.team_{team}.matches_won_this_series")!.Value(),
+ };
+ }
+
+ private static Player? ParsePlayerFromJObject(JObject jsonObject)
+ {
+ return new Player()
+ {
+ SteamId = jsonObject.SelectToken("player.steamid")!.Value()!,
+ Name = jsonObject.SelectToken("player.name")!.Value()!,
+ Team = jsonObject.SelectToken("player.team")!.Value()!,
+ Activity = jsonObject.SelectToken("player.activity")!.Value()!,
+ State = ParsePlayerStateFromJObject(jsonObject),
+ MatchStats = ParsePlayerMatchStatsFromJObject(jsonObject)
+ };
+ }
+
+ private static PlayerState ParsePlayerStateFromJObject(JObject jsonObject)
+ {
+ return new PlayerState()
+ {
+ Health = jsonObject.SelectToken($"player.state.health")!.Value(),
+ Armor = jsonObject.SelectToken($"player.state.armor")!.Value(),
+ Helmet = jsonObject.SelectToken($"player.state.helmet")!.Value(),
+ Flashed = jsonObject.SelectToken($"player.state.flashed")!.Value(),
+ Smoked = jsonObject.SelectToken($"player.state.smoked")!.Value(),
+ Burning = jsonObject.SelectToken($"player.state.burning")!.Value(),
+ Money = jsonObject.SelectToken($"player.state.money")!.Value(),
+ RoundKills = jsonObject.SelectToken($"player.state.round_kills")!.Value(),
+ RoundHs = jsonObject.SelectToken($"player.state.round_killhs")!.Value(),
+ EquipmentValue = jsonObject.SelectToken($"player.state.equip_value")!.Value(),
+ };
+ }
+
+ private static PlayerMatchStats ParsePlayerMatchStatsFromJObject(JObject jsonObject)
+ {
+ return new PlayerMatchStats()
+ {
+ Kills = jsonObject.SelectToken($"player.match_stats.kills")!.Value(),
+ Assists = jsonObject.SelectToken($"player.match_stats.assists")!.Value(),
+ Deaths = jsonObject.SelectToken($"player.match_stats.deaths")!.Value(),
+ MVPs = jsonObject.SelectToken($"player.match_stats.mvps")!.Value(),
+ Score = jsonObject.SelectToken($"player.match_stats.score")!.Value(),
+ };
+ }
+}
\ No newline at end of file
diff --git a/GameState/CS2GameState.cs b/GameState/CS2GameState.cs
new file mode 100644
index 0000000..48f2b1a
--- /dev/null
+++ b/GameState/CS2GameState.cs
@@ -0,0 +1,8 @@
+namespace CS2GSI.GameState;
+
+public struct CS2GameState
+{
+ public int Timestamp;
+ public Map? Map;
+ public Player? Player;
+}
\ No newline at end of file
diff --git a/GameState/Map.cs b/GameState/Map.cs
new file mode 100644
index 0000000..6e16e52
--- /dev/null
+++ b/GameState/Map.cs
@@ -0,0 +1,8 @@
+namespace CS2GSI.GameState;
+
+public struct Map
+{
+ public string Mode, Name, Phase;
+ public int Round, NumMatchesToWinSeries;
+ public Team TeamCT, TeamT;
+}
\ No newline at end of file
diff --git a/GameState/Player.cs b/GameState/Player.cs
new file mode 100644
index 0000000..9e0de63
--- /dev/null
+++ b/GameState/Player.cs
@@ -0,0 +1,10 @@
+namespace CS2GSI.GameState;
+
+public struct Player
+{
+ public string SteamId, Name, Activity;
+ public string? Team;
+ public int? ObserverSlot;
+ public PlayerState? State;
+ public PlayerMatchStats? MatchStats;
+}
\ No newline at end of file
diff --git a/GameState/PlayerMatchStats.cs b/GameState/PlayerMatchStats.cs
new file mode 100644
index 0000000..3b8ccd5
--- /dev/null
+++ b/GameState/PlayerMatchStats.cs
@@ -0,0 +1,6 @@
+namespace CS2GSI.GameState;
+
+public struct PlayerMatchStats
+{
+ public int Kills, Assists, Deaths, MVPs, Score;
+}
\ No newline at end of file
diff --git a/GameState/PlayerState.cs b/GameState/PlayerState.cs
new file mode 100644
index 0000000..e8ada4c
--- /dev/null
+++ b/GameState/PlayerState.cs
@@ -0,0 +1,7 @@
+namespace CS2GSI.GameState;
+
+public struct PlayerState
+{
+ public int Health, Armor, Flashed, Smoked, Burning, Money, RoundKills, RoundHs, EquipmentValue;
+ public bool Helmet;
+}
\ No newline at end of file
diff --git a/GameState/Team.cs b/GameState/Team.cs
new file mode 100644
index 0000000..c08eec7
--- /dev/null
+++ b/GameState/Team.cs
@@ -0,0 +1,6 @@
+namespace CS2GSI.GameState;
+
+public struct Team
+{
+ public int Score, ConsecutiveRoundLosses, TimeoutsRemaining, MatchesWonThisSeries;
+}
\ No newline at end of file