public LogData ParseLog(string filename) { try { var file = File.Open(filename, FileMode.Open); var bs = new BufferedStream(file); var stream = new StreamReader(bs); var summonerMap = new Dictionary<string, int>(); int netUID = -2; var mergedTeam = new List<Summoner>(); double startTime = -1, lastTimeStamp = -1; bool disconnect = false; DateTime startDate = new DateTime(); Match match; var ret = new LogData(); ret.LogFile = filename; string line; string gameMode = ""; HashSet<string> gameMutators = new HashSet<string>(); while ((line = stream.ReadLine()) != null) { string[] parts = line.Split(new char[] {'|'}, 5, StringSplitOptions.None); if (parts.Length == 1) { // Old format e.g. --- Log started at Sun Apr 29 23:34:01 2012 match = LOG_START_REGEX1.Match(line); if (match.Success) { var parsedDate = String.Format("{0} {1}, {2} {3}", match.Groups[2].Value, // month match.Groups[3].Value, // day match.Groups[5].Value, // year match.Groups[4].Value // time ); if (!DateTime.TryParse(parsedDate, out startDate)) { Logger.LogMessage(filename + ": Invalid date in " + match.Groups[0].Value); } } } // v6.6 and above remove the excessive "Xkb added" columns. if (parts.Length != 3 && parts.Length != 5) { continue; } double timeStamp = 0; if (!double.TryParse(parts[0].Trim(), NumberStyles.Number, new CultureInfo("en-US"), out timeStamp)) { // This line is corrupted. Ignore it continue; } lastTimeStamp = timeStamp; string text = parts.Last().Substring(1); if ((match = LOG_START_REGEX2.Match(text)).Success) { if (!DateTime.TryParse(match.Groups[1].Value, out startDate)) { Logger.LogMessage(filename + ": Invalid date " + match.Groups[1].Value); } } else if ((match = GAME_ID_REGEX.Match(text)).Success) { // Obtain game ID. ret.GameID = match.Groups[1].Value; if (match.Groups[3].Success) { ret.Server = match.Groups[3].Value; } } else if ((match = BUILD_REGEX.Match(text)).Success) { // game version ret.GameVersion = new Version(match.Groups[1].Value); } else if ((match = MAP_REGEX.Match(text)).Success) { // Obtain map ID int mapID = int.Parse(match.Groups[1].Value); if (!MapDictionary.TryGetValue(mapID, out ret.Map)) { ret.Map = "Unknown Map"; } } else if ((match = NET_UID_REGEX.Match(text)).Success) { // client's ID netUID = int.Parse(match.Groups[1].Value); } else if (text.Contains("Started ReplayDownloadManager")) { // indicates that this was a spectated game. ret.Spectated = true; } else if (text == "GAMESTATE_GAMELOOP Begin") { // this indicates the game actually loaded. startTime = timeStamp; Debug.Assert(!startDate.Equals(new DateTime()), "Game started with undefined start date"); ret.GameStartDate = startDate.AddSeconds(startTime); } else if ((match = KILLER_REGEX.Match(text)).Success && !ret.Spectated) { var killer = match.Groups[1].Value; if (summonerMap.ContainsKey(killer)) { ret.Deaths.Add(summonerMap[killer]); } else { // Most likely tower or minion. ret.Deaths.Add(-1); } } else if (text == "Disconnected") { disconnect = true; } else if (text == "End game message processing!") { // indicates game end. ret.GameLength = (int) (timeStamp - startTime + 0.5); disconnect = false; } else if (text == "Finished Play game" && ret.GameLength == 0) { // The end game message always comes first. If it didn't, that means we forcibly left the game. ret.GameLength = (int) (timeStamp - startTime + 0.5); ret.ExitCode = LogData.ExitCodes.LEAVE; } else if ((match = EXITCODE_REGEX.Match(text)).Success) { switch (match.Groups[1].Value) { case "WIN": ret.ExitCode = LogData.ExitCodes.WIN; break; case "LOSE": ret.ExitCode = LogData.ExitCodes.LOSE; break; case "ABANDON": ret.ExitCode = LogData.ExitCodes.LEAVE; break; } } else if ((match = GAME_MODE_REGEX.Match(text)).Success) { gameMode = match.Groups[1].Value.ToLower(); } else if ((match = GAME_MUTATOR_REGEX.Match(text)).Success) { gameMutators.Add(match.Groups[1].Value.ToLower()); } else if (text.Contains("TwistedAura.dds")) { ret.Map = "Twisted Treeline"; // 3v3 doesn't have a special game mode, but this texture gets loaded } else if (text.Contains(" SRUAP_")) { ret.Map = "Summoner's Rift (New)"; } else { if (ret.GameVersion >= CLIENT_ID_VERSION) { match = CHAMPION_REGEX1.Match(text); if (match.Success) { var summoner = new Summoner() { Champion = FixChampionName(match.Groups[1].Value), SkinID = int.Parse(match.Groups[2].Value), Name = match.Groups[5].Value }; var teamID = int.Parse(match.Groups[3].Value); var clientID = int.Parse(match.Groups[4].Value); if (clientID == -1) { ret.BotGame = true; summoner.IsBot = true; } List<Summoner> team = (teamID == 100 ? ret.BlueTeam : ret.PurpleTeam); if (!summonerMap.ContainsKey(summoner.Name)) { team.Add(summoner); summonerMap[summoner.Name] = summonerMap.Count; } if (!ret.Spectated && clientID == netUID) { ret.PlayerName = summoner.Name; } } } else { match = CHAMPION_REGEX2.Match(text); if (match.Success) { var summoner = new Summoner() { Champion = FixChampionName(match.Groups[1].Value), Name = match.Groups[4].Value }; if (match.Groups[3].Success) { summoner.SkinID = int.Parse(match.Groups[3].Value); } else { summoner.SkinID = -1; } // Guess the team.. might not be accurate for 1v5 bot games and such. if (!summonerMap.ContainsKey(summoner.Name)) { mergedTeam.Add(summoner); summonerMap[summoner.Name] = summonerMap.Count; } } } } } if (ret.Map == null) { if (gameMode == "classic") { ret.Map = "Summoner's Rift"; if (gameMutators.Contains("urf")) { ret.Map += " (URF)"; } } else if (gameMode == "aram") { ret.Map = "Howling Abyss"; } else if (gameMode == "odin") { ret.Map = "Crystal Scar"; } else if (gameMode == "ascension") { ret.Map = "Crystal Scar (Ascension)"; } } // Overrides existing Twisted Treeline detection. if (gameMutators.Contains("6v6")) { ret.Map = "Twisted Treeline (Hexakill)"; } if (startTime == -1) { return null; // Game crashed before loading. } if (ret.GameLength == 0) { // Game crashed in the middle somewhere. ret.GameLength = (int) (lastTimeStamp - startTime + 0.5); ret.ExitCode = LogData.ExitCodes.CRASH; } if (disconnect) { ret.ExitCode = LogData.ExitCodes.CRASH; } if (mergedTeam.Count > 0) { // Assume half the players are on both teams. Doesn't account for uneven teams, of course.. int l = (mergedTeam.Count + 1)/2; ret.BlueTeam = mergedTeam.Take(l).ToList(); ret.PurpleTeam = mergedTeam.Skip(l).ToList(); if (ret.BlueTeam.All((x) => x.Name.EndsWith(" Bot")) || ret.PurpleTeam.All((x) => x.Name.EndsWith(" Bot"))) { ret.BotGame = true; } } return ret; } catch (Exception ex) { Logger.LogException(ex); return null; } }
private void AddSummoner(Summoner s, FlowLayoutPanel flow, bool leftSide, bool isPlayer) { var label = new Label() { Text = leftSide ? s.Name + " (" + s.Champion + ")" : "(" + s.Champion + ") " + s.Name, Margin = new Padding(0, 2, 0, 3), Font = new Font(headerLabel.Font.FontFamily, 9.5f, isPlayer ? FontStyle.Bold : FontStyle.Regular), AutoSize = true, Cursor = Cursors.Hand, }; label.Click += (sender, e) => mainForm.OpenSummonerDetails(s.Name); var bitmap = Resources.ResourceManager.GetObject(Util.Sanitize(s.Champion)) as Bitmap; if (bitmap == null) { bitmap = Resources.unknown; } var icon = new PictureBox() { Width = 16, Height = 16, BackColor = Color.Silver, BackgroundImage = bitmap, }; flow.Controls.Add(icon); flow.Controls.Add(label); flow.SetFlowBreak(label, true); }