/* * Because we don't know the outcome of the round when parsing * results, we have to store values locally until the end of each * round when the */ public IEnumerable <TrainingResult> EnumerateTrainingResults() { while (_demoParser.ParseNextTick()) { if (snapshotResultThisTick) { var result = SnapshotCurrentResult(); if (result != null) { partialResults.Add(result); // Console.WriteLine("Snapshot. currentTick=" + currentTick + ", numPartialResults=" + partialResults.Count); } } foreach (var v in yieldResults) { yield return(v); } yieldResults.Clear(); snapshotResultThisTick = false; } }
private void addPlayers(String fileName) { var parser = new DemoParser(File.OpenRead(fileName)); parser.ParseHeader(); int count = 0; while (count < 10) { for (int i = 0; i < 100; i++) { parser.ParseNextTick(); } count = 0; foreach (var p in parser.PlayingParticipants) { count++; } } List <long> tempList = new List <long>(); foreach (var player in parser.PlayingParticipants) { tempList.Add(player.SteamID); } playersInFile.Add(fileName, tempList); }
private void timer1_Tick(object sender, EventArgs e) { if (!parser.ParseNextTick()) { timer1.Enabled = false; this.Close(); } }
private void FixedUpdate() { if (demoParser != null) { UpdateSeekBar(); UpdateRoundsText(); if (demoParser.CurrentTick != tickIndex) { Goto(tickIndex); } if (play && !isSeeking && !isBarSeeking && !isDone && Time.time >= lastTickPlayed + secondsPerTick) { lastTickPlayed = Time.time; demoParser.ParseNextTick(); tickIndex = demoParser.CurrentTick; } UpdateOverviewBlips(); if (threeDView) { UpdateCharacters(); } ResetTempValues(); } if (Time.time - winTextLastShown > winTextShowTime) { winText.gameObject.SetActive(false); } if ((playbackControlsView.IsShowing || playbackControlsView.IsVisible) && !isBarSeeking && play && Time.time - controlsToggledTime > controlsHideTime) { HideControls(); } playbackButtonImage.sprite = (play && !isDone) ? pauseSprite : playSprite; }
public DemoAnalysis ParseTheRest() { analysis.Metadata = parser.Header; while (parser.ParseNextTick()) { ; } analysis.IsFinished = true; analysis.Progress = 1.0; HandleRoundStart(null, new RoundStartedEventArgs()); return(analysis); }
//Initialisation step, should fire when parsing the demo for first time public static void getDataInstanceAsync(DemoParser parser, Action <float> updateProgress = null, Action <demodatainstance> getResult = null) //Report progress { BackgroundWorker bg = new BackgroundWorker(); demodatainstance testinstance = new demodatainstance(null); //Assign basic information testinstance.info.mapname = parser.Map; testinstance.info.ctName = parser.CTClanName; testinstance.info.tName = parser.TClanName; testinstance.info.serverName = parser.Header.ServerName; testinstance.info.ctScore = parser.CTScore; testinstance.info.tScore = parser.TScore; bg.DoWork += (sender, ee) => { //Subscribe to events here parser.WeaponFired += (object o, WeaponFiredEventArgs e) => { //Add the weapon fired position to that players most recent round testinstance.players[e.Shooter.EntityID].rounds.Last().shotsFired.Add(new vector3( e.Shooter.Position.X, e.Shooter.Position.Y, e.Shooter.Position.Z)); }; //Add a new round to each player on each team, on round start parser.RoundStart += (object o, RoundStartedEventArgs e) => { //foreach (p_Team recTeam in teams) //foreach (p_Player player in testinstance.players.Values.ToList()) // player.rounds.Add(new p_Round()); //Loop over each player on round start and assign the team to it foreach (DemoInfo.Player player in parser.PlayingParticipants) { if (player.IsAlive) { testinstance.players[player.EntityID].rounds.Add(new p_Round()); p_Team_Identifier tIdentify = p_Team_Identifier.counterterrorist; if (player.Team == Team.Terrorist) { tIdentify = p_Team_Identifier.terrorist; } testinstance.players[player.EntityID].rounds.Last().teamPlayedOnRound = tIdentify; } } }; //Log all player deaths parser.PlayerKilled += (object o, PlayerKilledEventArgs e) => { //Do a team check int team = 0; if (e.Victim.Team == Team.Terrorist) { team = 1; } //Add the player death testinstance.players[e.Victim.EntityID].deathPositions.Add(new vector3( e.Victim.Position.X, e.Victim.Position.Y, e.Victim.Position.Z)); }; int uProg = 0; int tickSwitch = 0; //Loop through ticks here while (parser.ParseNextTick() != false) { foreach (DemoInfo.Player player in parser.PlayingParticipants) { //Check if the player exists on the teams if (!testinstance.players.ContainsKey(player.EntityID)) { testinstance.players.Add(player.EntityID, new p_Player(player.Name, player.SteamID)); } } if (tickSwitch > 5) { foreach (DemoInfo.Player player in parser.PlayingParticipants) { //Check if the player is alive if (player.IsAlive) { //Add the players position testinstance.players[player.EntityID].rounds.Last().positions.Add(new vector3(player.Position.X, player.Position.Y, player.Position.Z)); } } tickSwitch = 0; } tickSwitch++; //Report its progress //updateProgress?.Invoke(parser.ParsingProgess); uProg++; if (uProg > 1000) { bg.ReportProgress(Convert.ToInt32(parser.ParsingProgess * 100)); uProg = 0; } } ee.Result = testinstance; }; bg.RunWorkerCompleted += (sender, e) => { demodatainstance result = (demodatainstance)e.Result; getResult?.Invoke(result); }; bg.WorkerReportsProgress = true; bg.ProgressChanged += (sender, e) => { updateProgress(e.ProgressPercentage); }; bg.RunWorkerAsync(); }
public demodata(string path) { DemoParser scan2 = new DemoParser(File.OpenRead(path)); scan2.RoundStart += (object o, RoundStartedEventArgs e) => { for (int i = 0; i < 2; i++) { foreach (List <List <vector3> > chunks in positions[i].Values.ToList()) { chunks.Add(new List <vector3>()); } } }; scan2.WeaponFired += (object o, WeaponFiredEventArgs e) => { shotPositions.Add(new vector3(e.Shooter.Position.X, e.Shooter.Position.Y, e.Shooter.Position.Z)); }; scan2.PlayerKilled += (object o, PlayerKilledEventArgs e) => { deathPositions.Add(new vector3(e.Victim.Position.X, e.Victim.Position.Y, e.Victim.Position.Z)); }; scan2.SmokeNadeStarted += (object o, SmokeEventArgs e) => { smokePositions.Add(new vector3(e.Position.X, e.Position.Y, e.Position.Z)); }; scan2.BombPlanted += (object o, BombEventArgs e) => { bombplantPositions.Add(new vector3(e.Player.Position.X, e.Player.Position.Y, e.Player.Position.Z)); }; scan2.ParseHeader(); Debug.progressBar("Reading", 0); positions.Add(new Dictionary <int, List <List <vector3> > >()); positions.Add(new Dictionary <int, List <List <vector3> > >()); int c = 0; try { while (scan2.ParseNextTick() != false) { foreach (DemoInfo.Player info in scan2.PlayingParticipants) { int team = 0; if (info.Team == Team.Terrorist) { team = 1; } if (!positions[team].ContainsKey(info.EntityID)) { positions[team].Add(info.EntityID, new List <List <vector3> >()); Debug.Log("+{0}/", info.EntityID); } if (info.IsAlive) { if (positions[team][info.EntityID].Count != 0) { positions[team][info.EntityID].Last().Add(new vector3(info.Position.X, info.Position.Y, info.Position.Z)); } } } c++; if (c % 500 == 0) { try { Debug.updateProgressBar(Convert.ToInt32(scan2.ParsingProgess * 100).Clamp(0, 100)); } catch { } } } } catch { Debug.Error("Something went wrong while reading stream"); } Debug.exitProgressBar(); }
public demodatainstance(DemoParser parser, Action <float> updateProgress = null) //Report progress { if (parser == null) { return; } //Assign basic information info.mapname = parser.Map; info.ctName = parser.CTClanName; info.tName = parser.TClanName; info.serverName = parser.Header.ServerName; info.ctScore = parser.CTScore; info.tScore = parser.TScore; #region event subscription //Subscribe to events here parser.WeaponFired += (object o, WeaponFiredEventArgs e) => { //Add the weapon fired position to that players most recent round players[e.Shooter.EntityID].rounds.Last().shotsFired.Add(new vector3( e.Shooter.Position.X, e.Shooter.Position.Y, e.Shooter.Position.Z)); }; //Add a new round to each player on each team, on round start parser.RoundStart += (object o, RoundStartedEventArgs e) => { //foreach (p_Team recTeam in teams) foreach (p_Player player in players.Values.ToList()) { player.rounds.Add(new p_Round()); } //Loop over each player on round start and assign the team to it foreach (DemoInfo.Player player in parser.PlayingParticipants) { p_Team_Identifier tIdentify = p_Team_Identifier.counterterrorist; if (player.Team == Team.Terrorist) { tIdentify = p_Team_Identifier.terrorist; } players[player.EntityID].rounds.Last().teamPlayedOnRound = tIdentify; } }; //Log all player deaths parser.PlayerKilled += (object o, PlayerKilledEventArgs e) => { //Do a team check int team = 0; if (e.Victim.Team == Team.Terrorist) { team = 1; } //Add the player death players[e.Victim.EntityID].deathPositions.Add(new vector3( e.Victim.Position.X, e.Victim.Position.Y, e.Victim.Position.Z)); }; #endregion try { int currentRound = 0; //Loop through ticks here while (parser.ParseNextTick() != false) { foreach (DemoInfo.Player player in parser.PlayingParticipants) { //Check if the player exists on the teams if (!players.ContainsKey(player.EntityID)) { players.Add(player.EntityID, new p_Player(player.Name, player.SteamID)); } //Check if the player is alive if (player.IsAlive) { //Add the players position players[player.EntityID].rounds[currentRound].positions.Add(new vector3(player.Position.X, player.Position.Y, player.Position.Z)); } } //Report its progress updateProgress?.Invoke(parser.ParsingProgess); } } catch { //TODO: Work out the error types Console.WriteLine("Error while parsing, usual..."); } }
async void ChangeLabel() { CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken t = cts.Token; this.FormClosing += (o, e) => { cts.Cancel(); }; p.Paint += (o, e) => { Graphics g = e.Graphics; using (SolidBrush selPen = new SolidBrush(Color.Blue)) { foreach (var p in parser.Participants) { if (p.Team != Team.Spectate && p.IsAlive) { float x = ((4400f - (rightBound - p.Position.X)) / 10f) / 440f * pwidth; float y = ((upperBound - p.Position.Y) / 10f) / 440f * pwidth; selPen.Color = p.Team == Team.CounterTerrorist ? Color.Blue : Color.Orange; selPen.Color = FlashedP.Select(pl => pl.Name).Contains(p.Name) ? Color.White : selPen.Color; g.FillEllipse(selPen, x - 5, y - 5, 10f, 10f); g.FillPolygon(selPen, new PointF[] { new PointF(x - 5f * (float)Math.Cos((p.ViewDirectionX + 90) / 180 * Math.PI), y + 5f * (float)Math.Sin((p.ViewDirectionX + 90) / 180 * Math.PI)), new PointF(x + 5f * (float)Math.Cos((p.ViewDirectionX + 90) / 180 * Math.PI), y - 5f * (float)Math.Sin((p.ViewDirectionX + 90) / 180 * Math.PI)), new PointF(x + 10f * (float)Math.Sin((p.ViewDirectionX + 90) / 180 * Math.PI), y + 10f * (float)Math.Cos((p.ViewDirectionX + 90) / 180 * Math.PI)) }); g.DrawString(p.Name, new Font("Arial", 8), selPen, x, y + 8, new StringFormat() { Alignment = StringAlignment.Center }); } } } using (SolidBrush smokeBrush = new SolidBrush(Color.Gray)) { foreach (var s in Smokes) { float x = ((4400f - (rightBound - s.X)) / 10f) / 440f * pwidth; float y = ((upperBound - s.Y) / 10f) / 440f * pwidth; g.FillEllipse(smokeBrush, x - 25, y + 25, 50f, 50f); } } }; //Invalidate(); parser = new DemoParser(File.OpenRead(filePath)); parser.ParseHeader(); lock (locker) { parser.TickDone += (o, e) => p.Invalidate(); parser.RoundEnd += (o, e) => { Smokes.Clear(); }; parser.SmokeNadeStarted += (o, e) => { Smokes.Add(new Nade() { X = e.Position.X, Y = e.Position.Y, ThrownBy = e.ThrownBy.Name }); }; parser.SmokeNadeEnded += (o, e) => { Smokes.Remove(Smokes.Single(s => s.X == e.Position.X && s.Y == e.Position.Y)); }; parser.FlashNadeExploded += (o, e) => { FlashedP.AddRange(e.FlashedPlayers); Task.Run(() => { Thread.Sleep(fps * 100); FlashedP.RemoveAll(pl => e.FlashedPlayers.Contains(pl)); }); }; parser.MatchStarted += (o, e) => { UpdateScoreTable(); }; parser.TickDone += (o, e) => { UpdateScoreTable(parser.PlayingParticipants.ToArray()); }; parser.PlayerKilled += (sender, e) => { if (dg.Rows.Count >= 5) { dg.Rows.RemoveAt(0); } dg.Rows.Add(e.Killer.Name, (e.Headshot ? "🗣 " : "") + e.Weapon?.Weapon.ToString(), e.Victim?.Name); UpdateScoreTable(e.Killer, e.Victim); }; } await Task.Run(() => { while (parser.ParseNextTick()) { if (t.IsCancellationRequested) { break; } ; Thread.Sleep(fps); while (!isPlaying) { Thread.Sleep(1); } } ; }); }
public void Stream() { if (port > -1) { if (gotvSocket != null) { if (gotvSocket.Available > 0) { //Debug.Log("Availability: " + gotvSocket.Available); try { byte[] received = new byte[2048]; int receivedBytes = gotvSocket.Receive(received); byte[] packetData = new byte[receivedBytes]; Array.ConstrainedCopy(received, 0, packetData, 0, receivedBytes); Debug.Log("Packet Length: " + receivedBytes); Debug.Log("Plain Text: " + GetStringUTF16(packetData)); Debug.Log("Numbers: " + ConvertToBunchNumbers(packetData)); ReadNetMessage(packetData); //packetData = ProtoBuf.ProtoReader.DirectReadBytes(new System.IO.MemoryStream(packetData), packetData.Length); //System.IO.MemoryStream decompressed = new System.IO.MemoryStream(); //BZip2.Decompress(new System.IO.MemoryStream(packetData), decompressed, true); //packetData = new byte[((int)decompressed.Length)]; //decompressed.Read(packetData, 0, packetData.Length); //Debug.Log("After ProtoBuf: " + GetStringUTF16(packetData)); } catch (System.Exception e) { Debug.Log(e.Message); } } } } if (play) { if (port > -1) { //set tick to last received } if (demoTicks != null && demoTicks.Count > 0) { if (playerObjects.Count < players.Count) { List <Player> missingKeys = new List <Player>(); foreach (KeyValuePair <Player, DemoEntity> entry in players) { if (!playerObjects.ContainsKey(entry.Key)) { missingKeys.Add(entry.Key); } } foreach (Player key in missingKeys) { GameObject entryObject = new GameObject(); CSGOPlayer entryPlayer = entryObject.AddComponent <CSGOPlayer>(); entryPlayer.replay = this; entryPlayer.playerInfo = players[key]; playerObjects.Add(key, entryPlayer); } } if (seekIndex < 0 || seekIndex >= demoTicks.Count) { seekIndex = 0; } if (port > 0) { demoParser.ParseNextTick(); seekIndex = demoTicks.Count - 1; } if (Time.time - previousTime >= playSpeed) { seekIndex += (int)((Time.time - previousTime) / playSpeed); previousTime = Time.time; } } } else { previousTime = Time.time; } /*if ((Input.GetMouseButton(0) || Input.GetMouseButton(1)) && !switchedTarget) * { * CameraControl theCam = Camera.main.GetComponent<CameraControl>(); * * if (playerObjects != null && playerObjects.Count > 0) * { * int currentIndex = -1; * if (theCam.target != null) * { * for (int i = 0; i < playerObjects.Count; i++) * { * if (playerObjects[i].entityID == theCam.target.gameObject.GetComponent<CSGOPlayer>().entityID) { currentIndex = i; break; } * } * //playerObjects.IndexOf(theCam.target.gameObject.GetComponent<CSGOPlayer>()); * } * //Debug.Log("Previous Index: " + currentIndex); * if (Input.GetMouseButton(0)) currentIndex++; * else if (Input.GetMouseButton(1)) currentIndex--; * if (currentIndex > playerObjects.Count - 1) currentIndex = 0; * if (currentIndex < 0) currentIndex = playerObjects.Count - 1; * * theCam.target = playerObjects[currentIndex].transform; * switchedTarget = true; * } * else * { * theCam.target = null; * } * } * else if (!Input.GetMouseButton(0) && !Input.GetMouseButton(1)) switchedTarget = false;*/ }
public void Parse(DemoParser parser) { Reset(); LoadMap(parser.Header.MapName); _playerData.Clear(); _playerKills.Kills.Clear(); _playerKills.KillsTicks.Clear(); _rounds.Clear(); var currentRoundInfo = new RoundInfo(); parser.RoundStart += (sender, e) => { currentRoundInfo.StartTick = parser.IngameTick; currentRoundInfo.TimeLimit = e.TimeLimit; currentRoundInfo.FragLimit = e.FragLimit; currentRoundInfo.Objective = e.Objective; }; parser.RoundEnd += (sender, e) => { currentRoundInfo.EndTick = parser.IngameTick; currentRoundInfo.Winner = e.Winner; currentRoundInfo.Reason = e.Reason; currentRoundInfo.Message = e.Message; _rounds.Add(currentRoundInfo); }; parser.PlayerKilled += (sender, e) => { var pk = new PlayerKill { Weapon = e.Weapon, VictimId = e.Victim.EntityID, VictimName = e.Victim.Name, VictimTeam = e.Victim.Team, PenetratedObjects = e.PenetratedObjects, Headshot = e.Headshot, AssistedFlash = e.AssistedFlash }; if (e.Killer != null) { pk.KillerId = e.Killer.EntityID; pk.KillerName = e.Killer.Name; pk.KillerTeam = e.Killer.Team; } if (e.Assister != null) { pk.AssisterId = e.Assister.EntityID; pk.AssisterName = e.Assister.Name; pk.AssisterTeam = e.Assister.Team; } _playerKills.KillsTicks.Add(parser.IngameTick); _playerKills.Kills.Add(pk); }; parser.PlayerDisconnect += (sender, e) => { if (_playerData.TryGetValue(e.Player.EntityID, out var data)) { data.StatesTicks.Add(parser.IngameTick); data.States.Add(new PlayerState { IsConnected = false, Name = e.Player.Name }); } }; try { while (parser.ParseNextTick()) { foreach (var player in parser.Participants) { PlayerData data; if (!_playerData.TryGetValue(player.EntityID, out data)) { data = new PlayerData(player.EntityID); _playerData.Add(player.EntityID, data); } var currentState = new PlayerState { IsConnected = true, IsAlive = player.IsAlive, Team = player.Team, Name = player.Name }; if (data.States.Count == 0 || data.States.Last() != currentState) { data.StatesTicks.Add(parser.IngameTick); data.States.Add(currentState); } if (player.IsAlive) { var currentPos = new PlayerPosition { PositionX = player.Position.X, PositionY = player.Position.Y, PositionZ = player.Position.Z, ViewDirectionX = player.ViewDirectionX, ViewDirectionY = player.ViewDirectionY, }; if (data.Positions.Count == 0 || data.Positions.Last() != currentPos) { data.PositionsTicks.Add(parser.IngameTick); data.Positions.Add(currentPos); } } var currentStats = new PlayerStatistics { Kills = player.AdditionaInformations.Kills, Deaths = player.AdditionaInformations.Deaths, Assists = player.AdditionaInformations.Assists, Score = player.AdditionaInformations.Score, MVPs = player.AdditionaInformations.MVPs, Ping = player.AdditionaInformations.Ping, Clantag = player.AdditionaInformations.Clantag, TotalCashSpent = player.AdditionaInformations.TotalCashSpent, }; if (data.Statistics.Count == 0 || data.Statistics.Last() != currentStats) { data.StatisticsTicks.Add(parser.IngameTick); data.Statistics.Add(currentStats); } } } } catch { } LastTick = parser.IngameTick; }
public Form1(string file) { filePath = file; this.SetStyle( ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true); this.WindowState = FormWindowState.Maximized; l = new Label(); //Controls.Add(l); Smokes = new List <Nade>(); FlashedP = new List <Player>(); Button btn = new Button() { Text = "Hit me!", Size = new Size() { Height = 100, Width = 100 } }; btn.Click += new EventHandler(ButtonClik); //Controls.Add(btn); table = new TableLayoutPanel() { Width = 600, Height = 400, AutoScroll = true }; table.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; table.CellBorderStyle = TableLayoutPanelCellBorderStyle.Inset; //parser.TickDone += (sender, e) => {table.Controls.Add(new Label() {Text = "tick", Width = 100 }, 0, table.RowCount); table.Update();}; //Controls.Add(table); dg = new DataGridView() { Width = 600, Height = 180, ReadOnly = true, AllowUserToAddRows = false, RowHeadersVisible = false, AllowUserToOrderColumns = false, AllowUserToResizeColumns = false, AllowUserToResizeRows = false }; dg.ClearSelection(); dg.SelectionChanged += (o, e) => { dg.ClearSelection(); }; dg.Columns.Add("killer", "Killer"); dg.Columns.Add("weapon", "Weapon"); dg.Columns.Add("victim", "Victim"); scoreTable = new DataGridView() { Location = new Point(0, 180), Width = 600, Height = 800, ReadOnly = true, AllowUserToAddRows = false, RowHeadersVisible = false, AllowUserToOrderColumns = false, AllowUserToResizeColumns = false, AllowUserToResizeRows = false }; scoreTable.ClearSelection(); dg.SelectionChanged += (o, e) => { dg.ClearSelection(); }; scoreTable.Columns.Add("items", "I"); scoreTable.Columns.Add("weapon", "Weapon"); scoreTable.Columns.Add("name", "Name"); scoreTable.Columns.Add("money", "Money"); scoreTable.Columns.Add("kills", "Kills"); scoreTable.Columns.Add("assists", "Assists"); scoreTable.Columns.Add("deaths", "Deaths"); scoreTable.Columns.Add("score", "Score"); scoreTable.Columns[1].Width = 60; scoreTable.Columns[3].Width = 100; scoreTable.Columns[4].Width = 40; scoreTable.Columns[5].Width = 40; scoreTable.Columns[6].Width = 40; scoreTable.Columns[7].Width = 40; Controls.Add(scoreTable); foreach (DataGridViewColumn column in dg.Columns) { column.SortMode = DataGridViewColumnSortMode.NotSortable; } Controls.Add(dg); p = new PictureBox() { Name = "Map", Location = new Point(600, 0), SizeMode = PictureBoxSizeMode.StretchImage, Size = new Size() { Width = (int)pwidth, Height = (int)pwidth }, Image = Image.FromFile("./Maps/Map.jpg") }; Button stopB = new Button() { Text = "||", Location = new Point(600, 900), Size = new Size(100, 50) }; Button normalB = new Button() { Text = ">", Location = new Point(700, 900), Size = new Size(100, 50) }; Button speedB = new Button() { Text = ">>", Location = new Point(800, 900), Size = new Size(100, 50) }; ComboBox box = new ComboBox() { Width = 100, Height = 50, Location = new Point(1600, 0), DataSource = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, DropDownStyle = ComboBoxStyle.DropDownList }; box.SelectionChangeCommitted += (o, e) => { isPlaying = false; Thread.Sleep(100); while (parser.TScore + parser.CTScore != (int)box.SelectedValue - 1) { parser.ParseNextTick(); } isPlaying = true; }; normalB.Click += NormalSpeedButton; speedB.Click += IncreaseSpeedButton; stopB.Click += StopSpeedButton; Controls.Add(p); Controls.Add(normalB); Controls.Add(speedB); Controls.Add(stopB); Controls.Add(box); InitializeComponent(); GamePaused += () => { Monitor.Enter(locker); trueParser = parser; parser = new IdleDemoParser(File.OpenRead(filePath)); parser.ParseHeader(); isPlaying = false; Monitor.Exit(locker); }; GameUnPaused += () => { parser = trueParser; isPlaying = true; }; ChangeLabel(); }
static List <PlayerMatchTrace> ParseFile(string fileName) { int PreviousTick = -1; List <PlayerMatchTrace> FullMatchTraces = new List <PlayerMatchTrace>(); // Consider only behaviour of active rounds and matches bool MatchStarted = false, RoundStarted = false; // Exclude matches divided in multiple demos bool CompleteMatch = false; // Current round info double ElapsedTime = 0; using (var fileStream = File.OpenRead(fileName)) { using (var parser = new DemoParser(fileStream)) { parser.ParseHeader(); string map = parser.Map; HashSet <string> validMaps = new HashSet <string>() { "de_inferno", "de_dust2", "de_mirage", "de_nuke" }; if (!validMaps.Contains(map) || parser.TickRate <= 0) { return(FullMatchTraces); } // The parser doesn't consider teams, but instead players with team tags which makes them hard to track. // Furthermore, scores can only be checked per team as in 'Terrorist' or 'CTerrorist', making it a pain in the ass // since teams are swapped after 15 rounds. // So a team tracker, to track team members and scores of the team TeamTracker TeamTracker = new TeamTracker(parser); parser.MatchStarted += (sender, e) => { // If it has been called twice, drop the previous records if (MatchStarted) { TeamTracker = new TeamTracker(parser); FullMatchTraces = new List <PlayerMatchTrace>(); } MatchStarted = true; }; parser.RoundStart += (sender, e) => { // Check if this is the first round in the current match if (!MatchStarted || RoundStarted || CompleteMatch) { return; } RoundStarted = true; ElapsedTime = 0; TeamTracker.CheckSwitch(parser.PlayingParticipants); }; parser.RoundEnd += (sender, e) => { if (!MatchStarted || CompleteMatch || !TeamTracker.ProperlySetTeams) { return; } RoundStarted = false; // Add score to the correct team TeamTracker.AddScore(e.Winner); TeamTracker.ResumeRound(); }; parser.TickDone += (sender, e) => { if (!RoundStarted || !MatchStarted) { return; } ElapsedTime += parser.TickTime; // Check if teams have been set if (!TeamTracker.ProperlySetTeams) { TeamTracker.CorrectTeams(parser.PlayingParticipants); return; } // Update team information in every tick TeamTracker.UpdatePlayerStats(parser.PlayingParticipants, parser.TickTime); TeamTracker.CalculatePlayerStats(ElapsedTime); }; parser.NadeReachedTarget += (sender, e) => { if (!RoundStarted || !MatchStarted || !TeamTracker.ProperlySetTeams) { return; } if (e.ThrownBy == null) { return; } }; parser.DecoyNadeStarted += (sender, e) => { if (!RoundStarted || !MatchStarted || !TeamTracker.ProperlySetTeams) { return; } if (e.ThrownBy == null) { return; } }; parser.SmokeNadeStarted += (sender, e) => { if (!RoundStarted || !MatchStarted || !TeamTracker.ProperlySetTeams) { return; } if (e.ThrownBy == null) { return; } }; parser.FireNadeStarted += (sender, e) => { if (!RoundStarted || !MatchStarted || !TeamTracker.ProperlySetTeams) { return; } if (e.ThrownBy == null) { return; } }; parser.WeaponFired += (sender, e) => { if (!RoundStarted || !MatchStarted || !TeamTracker.ProperlySetTeams) { return; } if (e.Weapon == null || e.Shooter == null) { return; } switch (e.Weapon.Class) { case EquipmentClass.Grenade: TeamTracker.GrenadeThrownEvent(e.Shooter.SteamID, e.Weapon); break; } }; parser.PlayerKilled += (sender, e) => { if (!TeamTracker.ProperlySetTeams) { return; } TeamTracker.KillEvent(e); if (e.Victim == null) { return; } if (e.Killer == null) { return; } }; parser.BombBeginPlant += (sender, e) => { }; //PlayerHurt is not used in all demos, so ignore for now. That's a headache for tomorrow. try { // If it breaks out of the loop, then it succesfully parsed the demo while (true) { // With this we advance through the demo PreviousTick = parser.CurrentTick; // Not sure why didn't count these as abnormal before if (!parser.ParseNextTick()) { if (!CompleteMatch) { foreach (var Trace in FullMatchTraces) { Trace.AbnormalMatch = true; Trace.Map = parser.Map; } } } ; // Sometimes it get stuck without proceeding through the ticks, // so we check make sure this is not the case if (parser.CurrentTick == PreviousTick) { return(new List <PlayerMatchTrace>()); } // End of match if (parser.TScore == 16 || parser.CTScore == 16 || (parser.TScore, parser.CTScore).Equals((15, 15))) { CompleteMatch = true; TeamTracker.ResumeMatch(); // Set winner of the match and refresh matchTraces // TODO: Meter estos en resumematch int WinnerTeam = TeamTracker.CheckWinner(parser.TScore, parser.CTScore); bool AbnormalMatch = TeamTracker.CompareScores(parser.TScore, parser.CTScore); FullMatchTraces.AddRange(TeamTracker.CompleteMatch()); foreach (var Trace in FullMatchTraces) { Trace.AbnormalMatch = AbnormalMatch; Trace.MatchWinner = Trace.InternalTeamId == WinnerTeam; } } if (CompleteMatch) { break; } } return(FullMatchTraces); } catch (Exception e) { // Sometimes demos are corrupt /* * Console.WriteLine(e.ToString()); * var st = new StackTrace(e, true); * var frame = st.GetFrame(0); * var line = frame.GetFileLineNumber(); * Console.WriteLine($"{st} {frame} {line}"); * Console.ReadKey(); */ return(new List <PlayerMatchTrace>()); } } } }
public static void GeneratePath(DemoParser parser, bool generatePNGs, bool generateCSV, bool analyzePath, String fileName) { Console.WriteLine(); Console.WriteLine(getTimeStamp() + "---PathGenerator---"); //Variables//////////////////////////////////////////////////////////////////////////////////// bool matchAlreadyAnalyzed = false; String ctTeamName = "", tTeamName = ""; int counter = 0; int resolutionDivider = 1; float minimapScale = 0; bool matchStarted = false; float maxX = 0, maxY = 0, minX = 0, minY = 0; Dictionary <long, IngamePlayer> ingamePlayerList = new Dictionary <long, IngamePlayer>(); Random randonGen = new Random(); long matchDBID = 0; Vector bombPlantPos = new Vector(0, 0, 0); bool bombPlantedInThisRound = false; var dbCon = new DBConnection(); int ctScoreDB = 0; int tScoreDB = 0; /////////////////////////////////////////////////////////////////////////////////////////////// parser.ParseHeader(); Console.WriteLine(getTimeStamp() + "Playing on " + parser.Map); //Get JSON with HLTV overview description of the map. string jsonContent = System.IO.File.ReadAllText("overviews/" + parser.Map + ".txt"); var hltvOverviewDescription = JsonConvert.DeserializeObject <dynamic>(jsonContent); //Set all the variables using the data from the JSON minimapScale = hltvOverviewDescription.scale; minX = hltvOverviewDescription.minPos_x; maxX = hltvOverviewDescription.maxPos_x; minY = hltvOverviewDescription.minPos_y; maxY = hltvOverviewDescription.maxPos_y; Console.WriteLine(getTimeStamp() + "Playing using " + parser.TickRate + " tickrate"); //Set the resolution of the analysis based on the TickRate if (parser.TickRate < 30) { resolutionDivider = 2; } else if (parser.TickRate > 30 && parser.TickRate < 60) { resolutionDivider = 4; } else if (parser.TickRate > 60) { resolutionDivider = 8; } // And now, generate the filename of the resulting file string outputFileName = "csv/" + fileName + "-paths.csv"; // and open it. var outputStream = new StreamWriter(outputFileName); if (generateCSV) { //And write a header so you know what is what in the resulting file outputStream.WriteLine(GenerateCSVHeader()); } //Check if the file has already been analyzed if (analyzePath) { if (dbCon.SelectMatch("SELECT * FROM `match` WHERE filename='" + fileName + "' LIMIT 1;")[0].Count != 0) { matchAlreadyAnalyzed = true; Console.WriteLine(getTimeStamp() + "Match already analyzed... Skipping Database Insertion."); } } parser.MatchStarted += (sender, e) => { matchStarted = true; //Check if the team names have already been parsed and saved them in vars. if (ctTeamName == "" && tTeamName == "" && parser.CTClanName != "" && parser.TClanName != "") { ctTeamName = parser.CTClanName; tTeamName = parser.TClanName; Console.WriteLine(getTimeStamp() + ctTeamName + " vs " + tTeamName); if (analyzePath && !matchAlreadyAnalyzed) { //Write match info into the database string matchInsertQuery = "INSERT INTO `match` (filename, team1, team2, score1, score2, mapName) VALUES ('" + fileName + "', '" + parser.CTClanName + "', '" + parser.TClanName + "', " + parser.CTScore + ", " + parser.TScore + ", '" + parser.Map + "');"; matchDBID = dbCon.Insert(matchInsertQuery); } } }; parser.RoundStart += (sender, e) => { bombPlantedInThisRound = false; foreach (var player in parser.PlayingParticipants) { ingamePlayerList[player.SteamID] = new IngamePlayer(player.SteamID, player.Team); } }; parser.PlayerKilled += (sender, e) => { if (ingamePlayerList.ContainsKey(e.Victim.SteamID)) { if (!bombPlantedInThisRound) { ingamePlayerList[e.Victim.SteamID].playerDeadBeforePlant = true; } ingamePlayerList[e.Victim.SteamID].playerDead = true; int x = (int)(Remap(e.Victim.Position.X, minX, maxX, 0, (float)hltvOverviewDescription.minimapRes)); int y = (int)(Remap(e.Victim.Position.Y, minY, maxY, 0, (float)hltvOverviewDescription.minimapRes)); ingamePlayerList[e.Victim.SteamID].deathPos = new Vector(x, y, e.Victim.Position.Z); } }; parser.NadeReachedTarget += (sender, e) => { if (e.ThrownBy != null && ingamePlayerList.ContainsKey(e.ThrownBy.SteamID)) { int x = (int)(Remap(e.Position.X, minX, maxX, 0, (float)hltvOverviewDescription.minimapRes)); int y = (int)(Remap(e.Position.Y, minY, maxY, 0, (float)hltvOverviewDescription.minimapRes)); if (!bombPlantedInThisRound) { ingamePlayerList[e.ThrownBy.SteamID].thrownGrenades.Add(new IngameGrenade(new Vector(x, y, e.Position.Z), e.NadeType, true)); } else { ingamePlayerList[e.ThrownBy.SteamID].thrownGrenades.Add(new IngameGrenade(new Vector(x, y, e.Position.Z), e.NadeType, false)); } } }; parser.BombPlanted += (sender, e) => { bombPlantedInThisRound = true; int x = (int)(Remap(e.Player.Position.X, minX, maxX, 0, (float)hltvOverviewDescription.minimapRes)); int y = (int)(Remap(e.Player.Position.Y, minY, maxY, 0, (float)hltvOverviewDescription.minimapRes)); bombPlantPos = new Vector(x, y, e.Player.Position.Z); }; //At the end of every round draw the strategic maps parser.RoundEnd += (sender, e) => { int playersOnEcoT = 0; int playersDeadOnCT = 0; String roundType = ""; bool enemyTeamWiped = false; //Increase counter for each player that is on an eco foreach (var player in parser.PlayingParticipants.Where(n => n.Team.Equals(Team.Terrorist))) { if (player.FreezetimeEndEquipmentValue <= 1750) { playersOnEcoT++; } } if (playersOnEcoT == 5) { roundType = "Eco"; } else if (playersOnEcoT > 0 && playersOnEcoT < 5) { roundType = "Force"; } else if (playersOnEcoT == 0) { roundType = "Full"; } //Increase counter for each player that is on T and dead foreach (var player in parser.PlayingParticipants.Where(n => n.Team.Equals(Team.CounterTerrorist))) { if (!player.IsAlive) { playersDeadOnCT++; } } if (playersDeadOnCT == 5) { enemyTeamWiped = true; } if (analyzePath && !matchAlreadyAnalyzed && matchDBID != 0 && ingamePlayerList.Count != 0) { long roundDBID = 0; //Write round info into the database string roundInsertQuery = "INSERT INTO `round` (matchID, roundType, bombPlanted, enemyTeamWiped, mapName) VALUES (" + matchDBID + ", '" + roundType + "', " + bombPlantedInThisRound + ", " + enemyTeamWiped + ", '" + parser.Map + "');"; roundDBID = dbCon.Insert(roundInsertQuery); //Write player steps into the databse foreach (var ingamePlayer in ingamePlayerList.Where(n => n.Value.playerTeam.Equals(Team.Terrorist))) { string playerStepsInsertQuery = "INSERT INTO `pathpoints` (roundID, steamID, X, Y, Z) VALUES "; int increaseBy = (ingamePlayer.Value.vectorList.Count / 100); Vector lastPlayerStep = new Vector(0, 0, 0); if (increaseBy != 0) { for (int i = 0; i < ingamePlayer.Value.vectorList.Count; i += increaseBy) { //Calculate distance between last inserted step and this step //double distance = Math.Sqrt(MyPow((lastPlayerStep.X - (int)ingamePlayer.Value.vectorList[i].X), 2) + MyPow((lastPlayerStep.Y - (int)ingamePlayer.Value.vectorList[i].Y), 2) + MyPow((lastPlayerStep.Z - (int)ingamePlayer.Value.vectorList[i].Z), 2)); int roundedX = ((int)Math.Round((int)ingamePlayer.Value.vectorList[i].X / 30.0)) * 30; int roundedY = ((int)Math.Round((int)ingamePlayer.Value.vectorList[i].Y / 30.0)) * 30; int roundedZ = ((int)Math.Round((int)ingamePlayer.Value.vectorList[i].Z / 30.0)) * 30; //if (distance >= 20) if (roundedX != lastPlayerStep.X && roundedY != lastPlayerStep.Y && roundedZ != lastPlayerStep.Z) { playerStepsInsertQuery += "(" + roundDBID + ", " + ingamePlayer.Value.steamID + ", " + (int)ingamePlayer.Value.vectorList[i].X + ", " + (int)ingamePlayer.Value.vectorList[i].Y + ", " + (int)ingamePlayer.Value.vectorList[i].Z + "),"; //playerStepsInsertQuery += "(" + roundDBID + ", " + ingamePlayer.Value.steamID + ", " + roundedX + ", " + roundedY + ", " + roundedZ + "),"; lastPlayerStep.X = roundedX; //(int)ingamePlayer.Value.vectorList[i].X; lastPlayerStep.Y = roundedY; //(int)ingamePlayer.Value.vectorList[i].Y; lastPlayerStep.Z = roundedZ; //(int)ingamePlayer.Value.vectorList[i].Z; } } //Remove last komma playerStepsInsertQuery = playerStepsInsertQuery.Substring(0, playerStepsInsertQuery.Length - 1); //Add semicolon playerStepsInsertQuery += ";"; dbCon.Insert(playerStepsInsertQuery); } } } if (analyzePath && !matchAlreadyAnalyzed) { dbCon.Insert("UPDATE `match` SET score1=" + parser.CTScore + ", score2=" + parser.TScore + " WHERE id=" + matchDBID); ctScoreDB = parser.CTScore; tScoreDB = parser.TScore; } if (generatePNGs) { //Begin drawing Bitmap bitmap = new Bitmap(1024, 1024); Graphics graphics = Graphics.FromImage(bitmap); if (ingamePlayerList.Count != 0) { //Draw Map background Image mapBackground = Image.FromFile("overviews/" + parser.Map + "_radar.png"); graphics.DrawImage(mapBackground, 0, 0); //Prepare minimap Icons Image deathIcon = Image.FromFile("mapIcons/death.png"); Image smokeIcon = Image.FromFile("mapIcons/smoke.png"); Image fireIcon = Image.FromFile("mapIcons/fire.png"); Image bombIcon = Image.FromFile("mapIcons/bomb.png"); int playerNumberT = 0, playerNumberCT = 0; int playersOnEcoCT = 0; foreach (var ingamePlayer in ingamePlayerList.Where(n => n.Value.playerTeam.Equals(Team.Terrorist))) { //Generate a random color for the player SolidBrush brush; playerNumberT++; switch (playerNumberT) { case 1: brush = new SolidBrush(Color.DarkRed); deathIcon = Image.FromFile("mapIcons/deathDarkRed.png"); break; case 2: brush = new SolidBrush(Color.DarkGreen); deathIcon = Image.FromFile("mapIcons/deathDarkGreen.png"); break; case 3: brush = new SolidBrush(Color.Blue); deathIcon = Image.FromFile("mapIcons/deathBlue.png"); break; case 4: brush = new SolidBrush(Color.Yellow); deathIcon = Image.FromFile("mapIcons/deathYellow.png"); break; case 5: brush = new SolidBrush(Color.Purple); deathIcon = Image.FromFile("mapIcons/deathPurple.png"); break; default: brush = new SolidBrush(Color.FromArgb(255, randonGen.Next(75, 255), randonGen.Next(75, 255), randonGen.Next(75, 255))); deathIcon = Image.FromFile("mapIcons/death.png"); break; } //Draw a dot for each step foreach (var step in ingamePlayer.Value.vectorList) { graphics.FillEllipse(brush, new Rectangle((int)step.X, (int)step.Y, 5, 5)); } //Draw thrown smokes foreach (var grenade in ingamePlayer.Value.thrownGrenades.Where(n => n.grenadeType.Equals(EquipmentElement.Smoke))) { if (grenade.thrownBeforePlant) { //Draw smokes twice to make them less transparence. graphics.DrawImage(smokeIcon, new Rectangle((int)grenade.destinationPos.X - 16, (int)grenade.destinationPos.Y - 16, 32, 32)); graphics.DrawImage(smokeIcon, new Rectangle((int)grenade.destinationPos.X - 16, (int)grenade.destinationPos.Y - 16, 32, 32)); } } //Draw thrown molotoves / flames foreach (var grenade in ingamePlayer.Value.thrownGrenades.Where(n => n.grenadeType.Equals(EquipmentElement.Molotov))) { if (grenade.thrownBeforePlant) { graphics.DrawImage(fireIcon, new Rectangle((int)grenade.destinationPos.X - 16, (int)grenade.destinationPos.Y - 16, 32, 32)); } } //Draw skulls where a player has died if (ingamePlayer.Value.playerDead && ingamePlayer.Value.playerDeadBeforePlant) { graphics.DrawImage(deathIcon, (int)ingamePlayer.Value.deathPos.X - 12, (int)ingamePlayer.Value.deathPos.Y - 12, 24, 24); } } //Draw the bomb if it's been planted if (bombPlantedInThisRound) { graphics.DrawImage(bombIcon, (int)bombPlantPos.X - 20, (int)bombPlantPos.Y - 20, 40, 40); } //Increase counter for each player that is on an eco foreach (var player in parser.PlayingParticipants.Where(n => n.Team.Equals(Team.Terrorist))) { if (player.FreezetimeEndEquipmentValue <= 1500) { playersOnEcoT++; } } //Write onto the picture what kind of buy the team is using if (playersOnEcoT == 5) { graphics.DrawString("Eco", new Font("Tahoma", 20), Brushes.White, new Rectangle(0, 0, 500, 200)); } else if (playersOnEcoT > 0 && playersOnEcoT < 5) { graphics.DrawString("Force Buy / Part Buy", new Font("Tahoma", 20), Brushes.White, new Rectangle(0, 0, 500, 200)); } else if (playersOnEcoT == 0) { graphics.DrawString("Full Buy", new Font("Tahoma", 20), Brushes.White, new Rectangle(0, 0, 500, 200)); } graphics.Dispose(); int rounds = parser.CTScore + parser.TScore; bitmap.Save(fileName + "_" + rounds + "_T.png", ImageFormat.Png); bitmap.Dispose(); //CT-Side///////////////////////////////////////////////////////////////////////////////////////////////////////// bitmap = new Bitmap(1024, 1024); graphics = Graphics.FromImage(bitmap); graphics.DrawImage(mapBackground, 0, 0); foreach (var ingamePlayer in ingamePlayerList.Where(n => n.Value.playerTeam.Equals(Team.CounterTerrorist))) { //Generate a random color for the player SolidBrush brush; playerNumberCT++; switch (playerNumberCT) { case 1: brush = new SolidBrush(Color.DarkRed); deathIcon = Image.FromFile("mapIcons/deathDarkRed.png"); break; case 2: brush = new SolidBrush(Color.DarkGreen); deathIcon = Image.FromFile("mapIcons/deathDarkGreen.png"); break; case 3: brush = new SolidBrush(Color.Blue); deathIcon = Image.FromFile("mapIcons/deathBlue.png"); break; case 4: brush = new SolidBrush(Color.Yellow); deathIcon = Image.FromFile("mapIcons/deathYellow.png"); break; case 5: brush = new SolidBrush(Color.Purple); deathIcon = Image.FromFile("mapIcons/deathPurple.png"); break; default: brush = new SolidBrush(Color.FromArgb(255, randonGen.Next(75, 255), randonGen.Next(75, 255), randonGen.Next(75, 255))); deathIcon = Image.FromFile("mapIcons/death.png"); break; } //Draw a dot for each step foreach (var step in ingamePlayer.Value.vectorList) { graphics.FillEllipse(brush, new Rectangle((int)step.X, (int)step.Y, 5, 5)); } //Draw thrown smokes foreach (var grenade in ingamePlayer.Value.thrownGrenades.Where(n => n.grenadeType.Equals(EquipmentElement.Smoke))) { //Draw smokes twice to make them less transparence. graphics.DrawImage(smokeIcon, new Rectangle((int)grenade.destinationPos.X - 16, (int)grenade.destinationPos.Y - 16, 32, 32)); graphics.DrawImage(smokeIcon, new Rectangle((int)grenade.destinationPos.X - 16, (int)grenade.destinationPos.Y - 16, 32, 32)); } //Draw thrown molotoves / flames foreach (var grenade in ingamePlayer.Value.thrownGrenades.Where(n => n.grenadeType.Equals(EquipmentElement.Incendiary))) { graphics.DrawImage(fireIcon, new Rectangle((int)grenade.destinationPos.X - 16, (int)grenade.destinationPos.Y - 16, 32, 32)); } //Draw skulls where a player has died if (ingamePlayer.Value.playerDead) { graphics.DrawImage(deathIcon, (int)ingamePlayer.Value.deathPos.X - 12, (int)ingamePlayer.Value.deathPos.Y - 12, 24, 24); } } //Increase counter for each player that is on an eco foreach (var player in parser.PlayingParticipants.Where(n => n.Team.Equals(Team.CounterTerrorist))) { if (player.FreezetimeEndEquipmentValue <= 1750) { playersOnEcoCT++; } } //Write onto the picture what kind of buy the team is using if (playersOnEcoCT == 5) { graphics.DrawString("Eco", new Font("Tahoma", 20), Brushes.White, new Rectangle(0, 0, 500, 200)); } else if (playersOnEcoCT > 0 && playersOnEcoCT < 5) { graphics.DrawString("Force Buy / Part Buy", new Font("Tahoma", 20), Brushes.White, new Rectangle(0, 0, 500, 200)); } else if (playersOnEcoCT == 0) { graphics.DrawString("Full Buy", new Font("Tahoma", 20), Brushes.White, new Rectangle(0, 0, 500, 200)); } graphics.Dispose(); rounds = parser.CTScore + parser.TScore; bitmap.Save(fileName + "_" + rounds + "_CT.png", ImageFormat.Png); bitmap.Dispose(); //System.Environment.Exit(1); } } }; parser.TickDone += (sender, e) => { if (counter % resolutionDivider == 0) { if (matchStarted) { foreach (var player in parser.PlayingParticipants) { if (player.IsAlive) { ingamePlayerList[player.SteamID].playerDead = false; if (generateCSV) { writePlayerPosToFile(outputStream, parser.CurrentTick, parser.CTScore + parser.TScore, player.Team, player.Name, player.SteamID, player.IsAlive, player.Position); } if (ingamePlayerList.ContainsKey(player.SteamID) && !bombPlantedInThisRound) { int x = (int)(Remap(player.Position.X, minX, maxX, 0, (float)hltvOverviewDescription.minimapRes)); int y = (int)(Remap(player.Position.Y, minY, maxY, 0, (float)hltvOverviewDescription.minimapRes)); ingamePlayerList[player.SteamID].vectorList.Add(new Vector(x, y, player.Position.Z)); } } } } } //Count the number of ticks counter++; }; //Iterate trough every tick in the demo file while (parser.ParseNextTick()) { } if (ctScoreDB > tScoreDB) { dbCon.Insert("UPDATE `match` SET score1=" + (ctScoreDB + 1) + ", score2=" + tScoreDB + " WHERE id=" + matchDBID); } else if (tScoreDB > ctScoreDB) { dbCon.Insert("UPDATE `match` SET score1=" + ctScoreDB + ", score2=" + (tScoreDB + 1) + " WHERE id=" + matchDBID); } Console.WriteLine(getTimeStamp() + "Parsed " + counter / resolutionDivider + " ticks of the original " + counter); }
/// <summary> /// Assembles the gamestate object from data given by the demoparser. /// </summary> /// <param name="parser"></param> /// <param name="path"></param> /// <returns></returns> override public void GenerateGamestate() { if (Csgoparser == null) { throw new Exception("No parser set"); } if (Csgoparser.Header == null) // Watch out for mapname peaks { Csgoparser.ParseHeader(); } #region Main Gameevents //Start writing the gamestate object Csgoparser.MatchStarted += (sender, e) => { hasMatchStarted = true; //Assign Gamemetadata GameState.Meta = Jsonparser.AssembleGamemeta(Csgoparser.Map, Csgoparser.TickRate, Csgoparser.PlayingParticipants); }; //Assign match object Csgoparser.WinPanelMatch += (sender, e) => { if (hasMatchStarted) { GameState.Match = Match; } hasMatchStarted = false; }; //Start writing a round object Csgoparser.RoundStart += (sender, e) => { if (hasMatchStarted) { hasRoundStarted = true; round_id++; CurrentRound.round_id = round_id; } }; //Add round object to match object Csgoparser.RoundEnd += (sender, e) => { if (hasMatchStarted) { if (hasRoundStarted) //TODO: maybe round fires false -> do in tickdone event (see github issues of DemoInfo) { CurrentRound.winner_team = e.Winner.ToString(); Match.Rounds.Add(CurrentRound); CurrentRound = new Round(); CurrentRound.ticks = new List <Tick>(); } hasRoundStarted = false; } }; Csgoparser.FreezetimeEnded += (object sender, FreezetimeEndedEventArgs e) => { if (hasMatchStarted) { hasFreeezEnded = true; //Just capture movement after freezetime has ended } }; #endregion #region Playerevents Csgoparser.WeaponFired += (object sender, WeaponFiredEventArgs we) => { if (hasMatchStarted) { CurrentTick.tickevents.Add(Jsonparser.AssembleWeaponFire(we)); } }; Csgoparser.PlayerSpotted += (sender, e) => { if (hasMatchStarted) { CurrentTick.tickevents.Add(Jsonparser.AssemblePlayerSpotted(e)); } }; Csgoparser.WeaponReload += (object sender, WeaponReloadEventArgs we) => { if (hasMatchStarted) { //tick.tickevents.Add(jsonparser.assembleWeaponReload(we)); } }; Csgoparser.WeaponFiredEmpty += (object sender, WeaponFiredEmptyEventArgs we) => { if (hasMatchStarted) { //tick.tickevents.Add(jsonparser.assembleWeaponFireEmpty(we)); } }; Csgoparser.PlayerJumped += (sender, e) => { if (hasMatchStarted) { if (e.Jumper != null) { //tick.tickevents.Add(jsonparser.assemblePlayerJumped(e)); //steppers.Add(e.Jumper); } } }; Csgoparser.PlayerFallen += (sender, e) => { if (hasMatchStarted) { if (e.Fallen != null) { //tick.tickevents.Add(jsonparser.assemblePlayerFallen(e)); } } }; Csgoparser.PlayerStepped += (sender, e) => { if (hasMatchStarted) { if (e.Stepper != null && Csgoparser.PlayingParticipants.Contains(e.Stepper)) { //Prevent spectating players from producing steps CurrentTick.tickevents.Add(Jsonparser.AssemblePlayerStepped(e)); alreadytracked.Add(e.Stepper); } } }; Csgoparser.PlayerKilled += (object sender, PlayerKilledEventArgs e) => { if (hasMatchStarted) { //the killer is null if victim is killed by the world - eg. by falling if (e.Killer != null) { CurrentTick.tickevents.Add(Jsonparser.AssemblePlayerKilled(e)); alreadytracked.Add(e.Killer); alreadytracked.Add(e.Victim); } } }; Csgoparser.PlayerHurt += (object sender, PlayerHurtEventArgs e) => { if (hasMatchStarted) { //the attacker is null if victim is damaged by the world - eg. by falling if (e.Attacker != null) { CurrentTick.tickevents.Add(Jsonparser.AssemblePlayerHurt(e)); alreadytracked.Add(e.Attacker); alreadytracked.Add(e.Victim); } } }; #endregion #region Nadeevents //Nade (Smoke Fire Decoy Flashbang and HE) events Csgoparser.ExplosiveNadeExploded += (object sender, GrenadeEventArgs e) => { if (e.ThrownBy != null && hasMatchStarted) { CurrentTick.tickevents.Add(Jsonparser.assembleNade(e, "hegrenade_exploded")); } }; Csgoparser.FireNadeStarted += (object sender, FireEventArgs e) => { if (e.ThrownBy != null && hasMatchStarted) { CurrentTick.tickevents.Add(Jsonparser.assembleNade(e, "firenade_exploded")); } }; Csgoparser.FireNadeEnded += (object sender, FireEventArgs e) => { if (e.ThrownBy != null && hasMatchStarted) { CurrentTick.tickevents.Add(Jsonparser.assembleNade(e, "firenade_ended")); } }; Csgoparser.SmokeNadeStarted += (object sender, SmokeEventArgs e) => { if (e.ThrownBy != null && hasMatchStarted) { CurrentTick.tickevents.Add(Jsonparser.assembleNade(e, "smoke_exploded")); } }; Csgoparser.SmokeNadeEnded += (object sender, SmokeEventArgs e) => { if (e.ThrownBy != null && hasMatchStarted) { CurrentTick.tickevents.Add(Jsonparser.assembleNade(e, "smoke_ended")); } }; Csgoparser.DecoyNadeStarted += (object sender, DecoyEventArgs e) => { if (e.ThrownBy != null && hasMatchStarted) { CurrentTick.tickevents.Add(Jsonparser.assembleNade(e, "decoy_exploded")); } }; Csgoparser.DecoyNadeEnded += (object sender, DecoyEventArgs e) => { if (e.ThrownBy != null && hasMatchStarted) { CurrentTick.tickevents.Add(Jsonparser.assembleNade(e, "decoy_ended")); } }; Csgoparser.FlashNadeExploded += (object sender, FlashEventArgs e) => { if (e.ThrownBy != null && hasMatchStarted) { CurrentTick.tickevents.Add(Jsonparser.assembleNade(e, "flash_exploded")); } }; /* * // Seems to be redundant with all exploded events * parser.NadeReachedTarget += (object sender, NadeEventArgs e) => * { * if (e.ThrownBy != null && hasMatchStarted) * tick.tickevents.Add(jsonparser.assembleNade(e, "nade_reachedtarget")); * }; */ #endregion #region Bombevents Csgoparser.BombAbortPlant += (object sender, BombEventArgs e) => { //tick.tickevents.Add(jsonparser.assembleBomb(e, "bomb_abort_plant")); }; Csgoparser.BombAbortDefuse += (object sender, BombDefuseEventArgs e) => { //tick.tickevents.Add(jsonparser.assembleBombDefuse(e, "bomb_abort_defuse")); }; Csgoparser.BombBeginPlant += (object sender, BombEventArgs e) => { //tick.tickevents.Add(jsonparser.assembleBomb(e, "bomb_begin_plant")); }; Csgoparser.BombBeginDefuse += (object sender, BombDefuseEventArgs e) => { //tick.tickevents.Add(jsonparser.assembleBombDefuse(e, "bomb_begin_defuse")); }; Csgoparser.BombPlanted += (object sender, BombEventArgs e) => { //tick.tickevents.Add(jsonparser.assembleBomb(e, "bomb_planted")); }; Csgoparser.BombDefused += (object sender, BombEventArgs e) => { //tick.tickevents.Add(jsonparser.assembleBomb(e, "bomb_defused")); }; Csgoparser.BombExploded += (object sender, BombEventArgs e) => { //tick.tickevents.Add(jsonparser.assembleBomb(e, "bomb_exploded")); }; Csgoparser.BombDropped += (object sender, BombDropEventArgs e) => { //tick.tickevents.Add(jsonparser.assembleBombState(e, "bomb_dropped")); }; Csgoparser.BombPicked += (object sender, BombPickUpEventArgs e) => { //tick.tickevents.Add(jsonparser.assembleBombState(e, "bomb_picked")); }; #endregion #region Serverevents Csgoparser.PlayerBind += (sender, e) => { if (hasMatchStarted && Csgoparser.PlayingParticipants.Contains(e.Player)) { Console.WriteLine("Tickid: " + tick_id); CurrentTick.tickevents.Add(Jsonparser.assemblePlayerBind(e.Player)); } }; Csgoparser.PlayerDisconnect += (sender, e) => { if (hasMatchStarted && Csgoparser.PlayingParticipants.Contains(e.Player)) { Console.WriteLine("Tickid: " + tick_id); CurrentTick.tickevents.Add(Jsonparser.assemblePlayerDisconnected(e.Player)); } }; Csgoparser.BotTakeOver += (sender, e) => { if (hasMatchStarted && Csgoparser.PlayingParticipants.Contains(e.Taker)) { Console.WriteLine("Tickid: " + tick_id); CurrentTick.tickevents.Add(Jsonparser.assemblePlayerTakeOver(e)); } }; /*parser.PlayerTeam += (sender, e) => * { * if (e.Swapped != null) * Console.WriteLine("Player swapped: " + e.Swapped.Name + " " + e.Swapped.SteamID + " Oldteam: "+ e.OldTeam + " Newteam: " + e.NewTeam + "IsBot: " + e.IsBot + "Silent: " + e.Silent); * };*/ #endregion #region Futureevents /* * //Extraevents maybe useful * parser.RoundFinal += (object sender, RoundFinalEventArgs e) => { * * }; * parser.RoundMVP += (object sender, RoundMVPEventArgs e) => { * * }; * parser.RoundOfficiallyEnd += (object sender, RoundOfficiallyEndedEventArgs e) => { * * }; * parser.LastRoundHalf += (object sender, LastRoundHalfEventArgs e) => { * * }; */ #endregion // TickDone at last!! Otherwise events following this region are not tracked #region Tickevent / Ticklogic //Assemble a tick object with the above gameevents Csgoparser.TickDone += (sender, e) => { if (!hasMatchStarted) //Dont count ticks if the game has not started already (dismissing warmup and knife-phase for official matches) { return; } // 8 = 250ms, 16 = 500ms usw var updaterate = 8 * (int)(Math.Ceiling(Csgoparser.TickRate / 32)); if (updaterate == 0) { throw new Exception("Updaterate cannot be Zero"); } // Dump playerpositions every at a given updaterate according to the tickrate if ((tick_id % updaterate == 0) && hasFreeezEnded) { foreach (var player in Csgoparser.PlayingParticipants.Where(player => !alreadytracked.Contains(player))) { CurrentTick.tickevents.Add(Jsonparser.AssemblePlayerPosition(player)); } } tick_id++; alreadytracked.Clear(); }; // // MAIN PARSING LOOP // try { //Parse tickwise and add the resulting tick to the round object while (Csgoparser.ParseNextTick()) { if (hasMatchStarted) { CurrentTick.tick_id = tick_id; //Tickevents were registered if (CurrentTick.tickevents.Count != 0) { CurrentRound.ticks.Add(CurrentTick); tickcount++; CurrentTick = new Tick(); CurrentTick.tickevents = new List <Event>(); } } } Console.WriteLine("Parsed ticks: " + tick_id + "\n"); Console.WriteLine("NOT empty ticks: " + tickcount + "\n"); } catch (System.IO.EndOfStreamException e) { Console.WriteLine("Problem with tick-parsing. Is your .dem valid? See this projects github page for more info.\n"); Console.WriteLine("Stacktrace: " + e.StackTrace + "\n"); Jsonparser.StopParser(); Watch.Stop(); } #endregion }
public static void Main(string[] args) { string header = string.Join( ",", "map", "tick", "timestamp", "event", "winner", "round", "t1_score", "t2_score", "x", "y", "view_x", "view_y", "player", "team", "side", "kills", "deaths", "money", "weapon", "alive", "freeze_equip_value", "current_equip_value", "last_alive_pos_x", "last_alive_pos_y", "attacker", "attacker_pos_x", "attacker_pos_y", "attacker_team", "attacker_side", "bomb_site", "bomb_status", "bomb_planttime" ); Console.WriteLine(header); var timer = new Stopwatch(); timer.Start(); foreach (var file in args) { using (var fs = File.OpenRead(file)) { using (var parser = new DemoParser(fs)) { parser.ParseHeader(); var outPrefix = parser.Header.Filestamp; bool started = false; parser.MatchStarted += (sender, e) => { started = true; var values = InitialValues(parser); values.Add("event", "round_start"); values.Add("map", parser.Header.MapName); Console.WriteLine(RowString(values)); }; while (!started) { parser.ParseNextTick(); } bool bombIsPlanted = false; parser.RoundStart += (sender, e) => { bombIsPlanted = false; var values = InitialValues(parser); values.Add("event", "round_start"); values.Add("map", parser.Header.MapName); Console.WriteLine(RowString(values)); }; parser.RoundEnd += (sender, e) => { var values = InitialValues(parser); values.Add("event", "round_end"); values.Add("winner", e.Winner.ToString()); values.Add("reason", e.Reason.ToString()); Console.WriteLine(RowString(values)); }; string bombPosX = "", bombPosY = ""; string site = ""; string status = ""; string planttime = ""; parser.BombPlanted += (sender, e) => { bombIsPlanted = true; bombPosX = e.Player.Position.X.ToString(); bombPosY = e.Player.Position.Y.ToString(); site = e.Site.ToString(); status = "planted"; planttime = parser.CurrentTime.ToString(); }; parser.BombExploded += (sender, e) => { status = "exploded"; }; parser.BombDefused += (sender, e) => { status = "defused"; }; parser.TickDone += (sender, e) => { if (parser.CurrentTick % 2 == 0) { if (bombIsPlanted) { var values = InitialValues(parser); values.Add("event", "bomb"); values.Add("x", bombPosX); values.Add("y", bombPosY); values.Add("bomb_site", site); values.Add("bomb_status", status); values.Add("bomb_planttime", planttime); Console.WriteLine(RowString(values)); } foreach (var player in parser.PlayingParticipants) { var values = InitialValues(parser); values.Add("event", "status"); values.Add("x", player.Position.X.ToString()); values.Add("y", player.Position.Y.ToString()); values.Add("view_x", player.ViewDirectionX.ToString()); values.Add("view_y", player.ViewDirectionY.ToString()); values.Add("player", player.Name); values.Add("team", GetTeam(parser, player)); values.Add("side", player.Team.ToString()); values.Add("kills", player.AdditionaInformations.Kills.ToString()); values.Add("deaths", player.AdditionaInformations.Deaths.ToString()); values.Add("money", player.Money.ToString()); if (player.ActiveWeapon != null) { values.Add("weapon", player.ActiveWeapon.Weapon.ToString()); } values.Add("alive", player.IsAlive.ToString()); values.Add("freeze_equip_value", player.FreezetimeEndEquipmentValue.ToString()); values.Add("current_equip_value", player.CurrentEquipmentValue.ToString()); values.Add("last_alive_pos_x", player.LastAlivePosition.X.ToString()); values.Add("last_alive_pos_y", player.LastAlivePosition.Y.ToString()); Console.WriteLine(RowString(values)); } } }; parser.WeaponFired += (sender, e) => { var values = InitialValues(parser); values.Add("event", "fire"); values.Add("x", e.Shooter.Position.X.ToString()); values.Add("y", e.Shooter.Position.Y.ToString()); values.Add("view_x", e.Shooter.ViewDirectionX.ToString()); values.Add("view_y", e.Shooter.ViewDirectionY.ToString()); values.Add("player", e.Shooter.Name); values.Add("team", GetTeam(parser, e.Shooter)); values.Add("side", e.Shooter.Team.ToString()); values.Add("weapon", e.Shooter.ActiveWeapon.Weapon.ToString()); Console.WriteLine(RowString(values)); }; parser.PlayerHurt += (sender, e) => { var values = InitialValues(parser); values.Add("event", "fire"); values.Add("x", e.Player.Position.X.ToString()); values.Add("y", e.Player.Position.Y.ToString()); values.Add("player", e.Player.Name); values.Add("team", GetTeam(parser, e.Player)); values.Add("side", e.Player.Team.ToString()); values.Add("weapon", e.Weapon.Weapon.ToString()); if (e.Attacker != null) { values.Add("attacker", e.Attacker.Name); values.Add("attacker_pos_x", e.Attacker.Position.X.ToString()); values.Add("attacker_pos_y", e.Attacker.Position.Y.ToString()); values.Add("attacker_team", GetTeam(parser, e.Attacker)); values.Add("attacker_side", e.Attacker.Team.ToString()); } Console.WriteLine(RowString(values)); }; parser.PlayerKilled += (sender, e) => { var values = InitialValues(parser); values.Add("event", "kill"); if (e.Victim != null) { values.Add("x", e.Victim.Position.X.ToString()); values.Add("y", e.Victim.Position.Y.ToString()); values.Add("player", e.Victim.Name); values.Add("team", GetTeam(parser, e.Victim)); values.Add("side", e.Victim.Team.ToString()); } values.Add("weapon", e.Weapon.Weapon.ToString()); if (e.Killer != null) { values.Add("attacker", e.Killer.Name); values.Add("attacker_pos_x", e.Killer.Position.X.ToString()); values.Add("attacker_pos_y", e.Killer.Position.Y.ToString()); values.Add("attacker_team", GetTeam(parser, e.Killer)); values.Add("attacker_side", e.Killer.Team.ToString()); } Console.WriteLine(RowString(values)); }; parser.ParseToEnd(); } } } timer.Stop(); Console.Error.WriteLine(timer.ElapsedMilliseconds); }
private void buttonAnalyze_Click(object sender, RoutedEventArgs e) { this.buttonLoad.IsEnabled = false; this.buttonAnalyze.IsEnabled = false; this.buttonPause.IsEnabled = true; this.t1 = Stopwatch.StartNew(); timer.Start(); demoParser.ParseDemo(false); bw = new BackgroundWorker(); bw.WorkerReportsProgress = true; bw.WorkerSupportsCancellation = true; // what to do in the background thread bw.DoWork += new DoWorkEventHandler( delegate(object o, DoWorkEventArgs args) { BackgroundWorker b = o as BackgroundWorker; while (demoParser.ParseNextTick() && !bw.CancellationPending) { if (demoParser.Header.PlaybackTicks == 0) { continue; } // report the progress in percent b.ReportProgress(Convert.ToInt32(((float)demoParser.CurrentTick / demoParser.Header.PlaybackTicks) * 100), demoParser); // ability to pause/resume thread locker.WaitOne(Timeout.Infinite); } if (bw.CancellationPending) { args.Cancel = true; return; } }); // what to do when progress changed (update the progress bar for example) bw.ProgressChanged += new ProgressChangedEventHandler( delegate(object o, ProgressChangedEventArgs args) { this.progressBar.Value = args.ProgressPercentage; this.labelProgress.Content = args.ProgressPercentage + "% - Tick : " + ((DemoParser)args.UserState).CurrentTick + "/" + ((DemoParser)args.UserState).Header.PlaybackTicks; }); // what to do when worker completes its task (notify the user) bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler( delegate(object o, RunWorkerCompletedEventArgs args) { bw.CancelAsync(); bw.Dispose(); t1.Stop(); timer.Stop(); this.textblockContent.Text += "Finished!" + Environment.NewLine; this.textblockContent.Text += "Time: " + t1.Elapsed.ToString(@"ss\.fffffff"); this.dataGridTeams.ItemsSource = demoParser.Teams; this.dataGridPlayers.ItemsSource = demoParser.Players; this.dataGridScoreboard.ItemsSource = scoreboardObserver.scoreBoard.GetLines(); SortScoreboard(); this.dataGridCheatAnalyze.ItemsSource = cheatObserver.results; this.buttonPause.IsEnabled = false; this.tabItemData.IsEnabled = true; this.tabItemScoreboard.IsEnabled = true; }); bw.Disposed += new EventHandler( delegate(object s, EventArgs ea) { this.buttonLoad.IsEnabled = true; }); bw.RunWorkerAsync(); }
public static void Main(string[] args) { using (var input = File.OpenRead(args[0])) { var parser = new DemoParser(input); parser.ParseHeader(); #if DEBUG Dictionary <Player, int> failures = new Dictionary <Player, int>(); parser.TickDone += (sender, e) => { //Problem: The HP coming from CCSPlayerEvent are sent 1-4 ticks later //I guess this is because the think()-method of the CCSPlayerResource isn't called //that often. Haven't checked though. foreach (var p in parser.PlayingParticipants) { //Make sure the array is never empty ;) failures[p] = failures.ContainsKey(p) ? failures[p] : 0; if (p.HP == p.AdditionaInformations.ScoreboardHP) { failures[p] = 0; } else { failures[p]++; //omg this is hacky. } //Okay, if it's wrong 2 seconds in a row, something's off //Since there should be a tick where it's right, right? //And if there's something off (e.g. two players are swapped) //there will be 2 seconds of ticks where it's wrong //So no problem here :) Debug.Assert( failures[p] < parser.TickRate * 2, string.Format( "The player-HP({0}) of {2} (Clan: {3}) and it's Scoreboard HP ({1}) didn't match for {4} ticks. ", p.HP, p.AdditionaInformations.ScoreboardHP, p.Name, p.AdditionaInformations.Clantag, parser.TickRate * 2 ) ); } }; if (args.Length >= 2) { // progress reporting requested using (var progressFile = File.OpenWrite(args[1])) using (var progressWriter = new StreamWriter(progressFile) { AutoFlush = false }) { int lastPercentage = -1; while (parser.ParseNextTick()) { var newProgress = (int)(parser.ParsingProgess * 100); if (newProgress != lastPercentage) { progressWriter.Write(lastPercentage = newProgress); progressWriter.Flush(); } } } return; } #endif parser.ParseToEnd(); } }
public static void Main(string[] args) { Console.WriteLine("Cool Stories."); using (var input = File.OpenRead(args[0])) { var parser = new DemoParser(input); parser.ParseHeader(); //Get map name string map = parser.Map; // And now, generate the filename of the resulting file string[] _output = args[0].Split(new[] { "/", "." }, StringSplitOptions.None); string demo_name = _output [_output.Length - 2]; string outputFileName = Math.Round(parser.TickRate) + "t_" + map + "_" + demo_name + ".csv"; // and open it. var outputStream = new StreamWriter(outputFileName); //Write to csv file headers first: //Write Header? Possible Issue is if Im writing multiple files so organising which is which is good. outputStream.WriteLine(WriteCSVLine("Steam_ID", "Name", "Tick", "Time", "Round", "Alive", "X", "Y", "Z", "VelX", "VelY", "VelZ", "ViewX", "ViewY", "ViewXPunchAngle", "ViewYPunchAngle", "AimXPunchAngle", "AimYPunchAngle", "AimXPunchVel", "AimYPunchVel", "ViewZOffset", "HasShot", "Weapon")); string outputFileHurt = Math.Round(parser.TickRate) + "t_" + map + "_" + demo_name + "_" + "attackinfo.csv"; var outputHurtStream = new StreamWriter(outputFileHurt); outputHurtStream.WriteLine(WriteCSVLine("Tick", "Attacker", "Victim", "HitGroup", "Weapon")); //PARSING GOES HERE int round_total = 0; int roundCSV = 0; Dictionary <Player, int> failures = new Dictionary <Player, int>(); parser.TickDone += (sender, e) => { //Problem: The HP coming from CCSPlayerEvent are sent 1-4 ticks later //I guess this is because the think()-method of the CCSPlayerResource isn't called //that often. Haven't checked though. foreach (var p in parser.PlayingParticipants) { var wep = "None"; if (p.ActiveWeapon != null && p.ActiveWeapon.OriginalString != null) { wep = p.ActiveWeapon.Weapon.ToString(); } // ID ; Tick ; Time ; outputStream.WriteLine(WriteCSVLine(p.SteamID, p.Name, parser.IngameTick, parser.CurrentTime, roundCSV, p.IsAlive, p.Position.X, p.Position.Y, p.Position.Z, p.Velocity.X, p.Velocity.Y, p.Velocity.Z, p.ViewDirectionX, p.ViewDirectionY, p.ViewPunchAngle.X, p.ViewPunchAngle.Y, p.AimPunchAngle.X, p.AimPunchAngle.Y, p.AimPunchVel.X, p.AimPunchVel.Y, p.ViewOffsetZ, p.HasShot, wep)); //Okay, if it's wrong 2 seconds in a row, something's off //Since there should be a tick where it's right, right? //And if there's something off (e.g. two players are swapped) //there will be 2 seconds of ticks where it's wrong //So no problem here :) p.HasShot = false; } }; Dictionary <Player, int> killsThisRound = new Dictionary <Player, int> (); parser.PlayerKilled += (object sender, PlayerKilledEventArgs e) => { //the killer is null if you're killed by the world - eg. by falling if (e.Killer != null) { if (!killsThisRound.ContainsKey(e.Killer)) { killsThisRound[e.Killer] = 0; } //Remember how many kills each player made this rounds killsThisRound[e.Killer]++; } }; parser.PlayerHurt += (object sender, PlayerHurtEventArgs e) => { //TODO: Test if The attacker is null if the world damages the player? if (e.Attacker != null) { int health = e.Health; outputHurtStream.WriteLine(WriteCSVLine(parser.IngameTick, e.Attacker.SteamID, e.Player.SteamID, e.Hitgroup.ToString(), e.Weapon.Weapon.ToString())); } else { outputHurtStream.WriteLine(WriteCSVLine(parser.IngameTick, "World", e.Player.SteamID, e.Hitgroup.ToString(), "None")); } }; parser.FreezetimeEnded += (object sender, FreezetimeEndedEventArgs e) => { round_total += 1; roundCSV = round_total; }; parser.RoundOfficiallyEnd += (object sender, RoundOfficiallyEndedEventArgs e) => { roundCSV = 0; }; parser.WeaponFired += (object sender, WeaponFiredEventArgs e) => { // e.Shooter.ActiveWeapon; e.Shooter.HasShot = true; //var _tick = parser.IngameTick; //var bleh_0 = 0; }; if (args.Length >= 2) { // progress reporting requested using (var progressFile = File.OpenWrite(args[1])) using (var progressWriter = new StreamWriter(progressFile) { AutoFlush = false }) { int lastPercentage = -1; while (parser.ParseNextTick()) { var newProgress = (int)(parser.ParsingProgess * 100); if (newProgress != lastPercentage) { progressWriter.Write(lastPercentage = newProgress); progressWriter.Flush(); } } } return; } parser.ParseToEnd(); //END: Closes File outputStream.Close(); outputHurtStream.Close(); int x = 5; x += 2; } }