private void ParseLines() { List <RoundInfo> round = new List <RoundInfo>(); List <RoundInfo> allStats = new List <RoundInfo>(); LogRound logRound = new LogRound(); while (!stop) { try { lock (lines) { for (int i = 0; i < lines.Count; i++) { LogLine line = lines[i]; if (ParseLine(line, round, logRound)) { allStats.AddRange(round); } } if (allStats.Count > 0) { OnParsedLogLines?.Invoke(allStats); allStats.Clear(); } lines.Clear(); } } catch (Exception ex) { OnError?.Invoke(ex.ToString()); } Thread.Sleep(UpdateDelay); } }
private bool ParseLine(LogLine line, List <RoundInfo> round, LogRound logRound) { int index; if ((index = line.Line.IndexOf("[StateGameLoading] Loading game level scene", StringComparison.OrdinalIgnoreCase)) > 0) { logRound.Info = new RoundInfo(); int index2 = line.Line.IndexOf(' ', index + 44); if (index2 < 0) { index2 = line.Line.Length; } logRound.Info.SceneName = line.Line.Substring(index + 44, index2 - index - 44); logRound.FindingPosition = false; round.Add(logRound.Info); } else if (logRound.Info != null && (index = line.Line.IndexOf("[StateGameLoading] Finished loading game level", StringComparison.OrdinalIgnoreCase)) > 0) { int index2 = line.Line.IndexOf(". ", index + 62); if (index2 < 0) { index2 = line.Line.Length; } logRound.Info.Name = line.Line.Substring(index + 62, index2 - index - 62); logRound.Info.Round = round.Count; logRound.Info.Start = line.Date; logRound.Info.InParty = logRound.CurrentlyInParty; logRound.Info.PrivateLobby = logRound.PrivateLobby; logRound.Info.GameDuration = logRound.Duration; logRound.CountingPlayers = true; logRound.Info.IsFinal = logRound.IsFinal || (!logRound.HasIsFinal && LevelStats.SceneToRound.TryGetValue(logRound.Info.SceneName, out string roundName) && LevelStats.ALL.TryGetValue(roundName, out LevelStats stats) && stats.IsFinal); } else if ((index = line.Line.IndexOf("[StateMatchmaking] Begin matchmaking", StringComparison.OrdinalIgnoreCase)) > 0 || (index = line.Line.IndexOf("[GameStateMachine] Replacing FGClient.StateMainMenu with FGClient.StatePrivateLobby", StringComparison.OrdinalIgnoreCase)) > 0) { logRound.PrivateLobby = line.Line.IndexOf("StatePrivateLobby") > 0; logRound.CurrentlyInParty = logRound.PrivateLobby || !line.Line.Substring(index + 37).Equals("solo", StringComparison.OrdinalIgnoreCase); if (logRound.Info != null) { if (logRound.Info.End == DateTime.MinValue) { logRound.Info.End = line.Date; } logRound.Info.Playing = false; } logRound.FindingPosition = false; Stats.InShow = true; round.Clear(); logRound.Info = null; } else if ((index = line.Line.IndexOf("NetworkGameOptions: durationInSeconds=", StringComparison.OrdinalIgnoreCase)) > 0) { int nextIndex = line.Line.IndexOf(" ", index + 38); logRound.Duration = int.Parse(line.Line.Substring(index + 38, nextIndex - index - 38)); index = line.Line.IndexOf("isFinalRound=", StringComparison.OrdinalIgnoreCase); logRound.HasIsFinal = index > 0; index = line.Line.IndexOf("isFinalRound=True", StringComparison.OrdinalIgnoreCase); logRound.IsFinal = index > 0; } else if (logRound.Info != null && logRound.CountingPlayers && (line.Line.IndexOf("[ClientGameManager] Finalising spawn", StringComparison.OrdinalIgnoreCase) > 0 || line.Line.IndexOf("[ClientGameManager] Added player ", StringComparison.OrdinalIgnoreCase) > 0)) { logRound.Info.Players++; } else if ((index = line.Line.IndexOf("[ClientGameManager] Handling bootstrap for local player FallGuy [", StringComparison.OrdinalIgnoreCase)) > 0) { int prevIndex = line.Line.IndexOf(']', index + 65); logRound.CurrentPlayerID = line.Line.Substring(index + 65, prevIndex - index - 65); } else if (logRound.Info != null && line.Line.IndexOf($"[ClientGameManager] Handling unspawn for player FallGuy [{logRound.CurrentPlayerID}]", StringComparison.OrdinalIgnoreCase) > 0) { if (logRound.Info.End == DateTime.MinValue) { logRound.Info.Finish = line.Date; } else { logRound.Info.Finish = logRound.Info.End; } logRound.FindingPosition = true; } else if (logRound.Info != null && logRound.FindingPosition && (index = line.Line.IndexOf("[ClientGameSession] NumPlayersAchievingObjective=")) > 0) { int position = int.Parse(line.Line.Substring(index + 49)); if (position > 0) { logRound.FindingPosition = false; logRound.Info.Position = position; } } else if (logRound.Info != null && line.Line.IndexOf("Client address: ", StringComparison.OrdinalIgnoreCase) > 0) { index = line.Line.IndexOf("RTT: "); if (index > 0) { int msIndex = line.Line.IndexOf("ms", index); logRound.LastPing = int.Parse(line.Line.Substring(index + 5, msIndex - index - 5)); } } else if (logRound.Info != null && line.Line.IndexOf("[GameSession] Changing state from Countdown to Playing", StringComparison.OrdinalIgnoreCase) > 0) { logRound.Info.Start = line.Date; logRound.Info.Playing = true; logRound.CountingPlayers = false; } else if (logRound.Info != null && (line.Line.IndexOf("[GameSession] Changing state from Playing to GameOver", StringComparison.OrdinalIgnoreCase) > 0 || line.Line.IndexOf("Changing local player state to: SpectatingEliminated", StringComparison.OrdinalIgnoreCase) > 0 || line.Line.IndexOf("[GlobalGameStateClient] SwitchToDisconnectingState", StringComparison.OrdinalIgnoreCase) > 0 || line.Line.IndexOf("[GameStateMachine] Replacing FGClient.StatePrivateLobby with FGClient.StateMainMenu", StringComparison.OrdinalIgnoreCase) > 0)) { if (logRound.Info.End == DateTime.MinValue) { logRound.Info.End = line.Date; } logRound.Info.Playing = false; } else if (line.Line.IndexOf("[StateMainMenu] Loading scene MainMenu", StringComparison.OrdinalIgnoreCase) > 0) { if (logRound.Info != null) { if (logRound.Info.End == DateTime.MinValue) { logRound.Info.End = line.Date; } logRound.Info.Playing = false; } logRound.FindingPosition = false; logRound.CountingPlayers = false; Stats.InShow = false; } else if (line.Line.IndexOf(" == [CompletedEpisodeDto] ==", StringComparison.OrdinalIgnoreCase) > 0) { if (logRound.Info == null) { return(false); } RoundInfo temp = null; StringReader sr = new StringReader(line.Line); string detail; bool foundRound = false; int maxRound = 0; DateTime showStart = DateTime.MinValue; while ((detail = sr.ReadLine()) != null) { if (detail.IndexOf("[Round ", StringComparison.OrdinalIgnoreCase) == 0) { foundRound = true; int roundNum = (int)detail[7] - 0x30 + 1; string roundName = detail.Substring(11, detail.Length - 12); if (roundNum - 1 < round.Count) { if (roundNum > maxRound) { maxRound = roundNum; } temp = round[roundNum - 1]; if (string.IsNullOrEmpty(temp.Name) || !temp.Name.Equals(roundName, StringComparison.OrdinalIgnoreCase)) { return(false); } temp.VerifyName(); if (roundNum == 1) { showStart = temp.Start; } temp.ShowStart = showStart; temp.Playing = false; temp.Round = roundNum; logRound.PrivateLobby = temp.PrivateLobby; logRound.CurrentlyInParty = temp.InParty; } else { return(false); } if (temp.End == DateTime.MinValue) { temp.End = line.Date; } if (temp.Start == DateTime.MinValue) { temp.Start = temp.End; } if (!temp.Finish.HasValue) { temp.Finish = temp.End; } } else if (foundRound) { if (detail.IndexOf("> Position: ", StringComparison.OrdinalIgnoreCase) == 0) { temp.Position = int.Parse(detail.Substring(12)); } else if (detail.IndexOf("> Team Score: ", StringComparison.OrdinalIgnoreCase) == 0) { temp.Score = int.Parse(detail.Substring(14)); } else if (detail.IndexOf("> Qualified: ", StringComparison.OrdinalIgnoreCase) == 0) { char qualified = detail[13]; temp.Qualified = qualified == 'T'; temp.Finish = temp.Qualified ? temp.Finish : null; } else if (detail.IndexOf("> Bonus Tier: ", StringComparison.OrdinalIgnoreCase) == 0 && detail.Length == 15) { char tier = detail[14]; temp.Tier = (int)tier - 0x30 + 1; } else if (detail.IndexOf("> Kudos: ", StringComparison.OrdinalIgnoreCase) == 0) { temp.Kudos += int.Parse(detail.Substring(9)); } else if (detail.IndexOf("> Bonus Kudos: ", StringComparison.OrdinalIgnoreCase) == 0) { temp.Kudos += int.Parse(detail.Substring(15)); } else if (detail.IndexOf("> Fame: ", StringComparison.OrdinalIgnoreCase) == 0) { temp.Fame += int.Parse(detail.Substring(8)); } else if (detail.IndexOf("> Bonus Fame: ", StringComparison.OrdinalIgnoreCase) == 0) { temp.Fame += int.Parse(detail.Substring(14)); } } } if (round.Count > maxRound) { return(false); } logRound.Info = round[round.Count - 1]; DateTime showEnd = logRound.Info.End; for (int i = 0; i < round.Count; i++) { round[i].ShowEnd = showEnd; } if (logRound.Info.Qualified) { logRound.Info.Crown = true; } logRound.Info = null; Stats.InShow = false; Stats.EndedShow = true; return(true); } return(false); }
private void ReadLogFile() { running = true; List <LogLine> tempLines = new List <LogLine>(); DateTime lastDate = DateTime.MinValue; bool completed = false; string currentFilePath = prevFilePath; long offset = 0; while (!stop) { try { if (File.Exists(currentFilePath)) { using (FileStream fs = new FileStream(currentFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { tempLines.Clear(); if (fs.Length > offset) { fs.Seek(offset, SeekOrigin.Begin); LineReader sr = new LineReader(fs); string line; DateTime currentDate = lastDate; while ((line = sr.ReadLine()) != null) { LogLine logLine = new LogLine(line, sr.Position); if (logLine.IsValid) { int index; if ((index = line.IndexOf("[GlobalGameStateClient].PreStart called at ")) > 0) { currentDate = DateTime.SpecifyKind(DateTime.Parse(line.Substring(index + 43, 19)), DateTimeKind.Utc); OnNewLogFileDate?.Invoke(currentDate); } if (currentDate != DateTime.MinValue) { if (currentDate.TimeOfDay.TotalSeconds - logLine.Time.TotalSeconds > 60000) { currentDate = currentDate.AddDays(1); } currentDate = currentDate.AddSeconds(logLine.Time.TotalSeconds - currentDate.TimeOfDay.TotalSeconds); logLine.Date = currentDate; } if (line.IndexOf(" == [CompletedEpisodeDto] ==") > 0) { StringBuilder sb = new StringBuilder(line); sb.AppendLine(); while ((line = sr.ReadLine()) != null) { LogLine temp = new LogLine(line, fs.Position); if (temp.IsValid) { logLine.Line = sb.ToString(); logLine.Offset = sr.Position; tempLines.Add(logLine); tempLines.Add(temp); break; } else if (!string.IsNullOrEmpty(line)) { sb.AppendLine(line); } } } else { tempLines.Add(logLine); } } else if (logLine.Line.IndexOf("Client address: ", StringComparison.OrdinalIgnoreCase) > 0) { tempLines.Add(logLine); } } } else if (offset > fs.Length) { offset = 0; } } } if (tempLines.Count > 0) { List <RoundInfo> round = new List <RoundInfo>(); LogRound logRound = new LogRound(); List <LogLine> currentLines = new List <LogLine>(); for (int i = 0; i < tempLines.Count; i++) { LogLine line = tempLines[i]; currentLines.Add(line); if (ParseLine(line, round, logRound)) { lastDate = line.Date; offset = line.Offset; lock (lines) { lines.AddRange(currentLines); currentLines.Clear(); } } else if (line.Line.IndexOf("[StateMatchmaking] Begin matchmaking", StringComparison.OrdinalIgnoreCase) > 0 || line.Line.IndexOf("[GameStateMachine] Replacing FGClient.StateMainMenu with FGClient.StatePrivateLobby", StringComparison.OrdinalIgnoreCase) > 0) { offset = i > 0 ? tempLines[i - 1].Offset : offset; lastDate = line.Date; } } if (logRound.LastPing != 0) { Stats.LastServerPing = logRound.LastPing; } OnParsedLogLinesCurrent?.Invoke(round); } if (!completed) { completed = true; offset = 0; currentFilePath = filePath; } } catch (Exception ex) { OnError?.Invoke(ex.ToString()); } Thread.Sleep(UpdateDelay); } running = false; }