public static bool UpdateDamageInformation(Dictionary <string, Dictionary <string, DamageEntry> > damageDealt, bool healing = false) { bool newDamage = false; Dictionary <string, DamageData> totalResults = healing ? totalHealingResults : totalDamageResults; lock (totalResults) { foreach (KeyValuePair <string, Dictionary <string, DamageEntry> > kvp in damageDealt) { string player = kvp.Key; Dictionary <string, DamageEntry> playerDamage = kvp.Value; if (!totalResults.ContainsKey(player)) { totalResults.Add(player, new DamageData { damagePerMinute = new Dictionary <string, DamageEntry>(), totalDamage = 0 }); } DamageData data = totalResults[player]; foreach (KeyValuePair <string, DamageEntry> kvp2 in playerDamage) { string timestamp = kvp2.Key; DamageEntry entry = kvp2.Value; int damage = entry.damage; // if the damage for the given timestamp does not exist yet, add it if (!data.damagePerMinute.ContainsKey(timestamp)) { data.damagePerMinute.Add(timestamp, entry); data.totalDamage += damage; newDamage = true; } // if it does exist, select the biggest of the two // the reason we select the biggest of the two is: // - if the timestamp is 'the current time', totalDamageResults may hold an old value, so we update it // - if timestamp is old, a part of the log for the time could have already been removed (because the log was full) // so the 'new' damage is only part of the damage for this timestamp else if (data.damagePerMinute[timestamp].damage < damage) { data.totalDamage += damage - data.damagePerMinute[timestamp].damage; data.damagePerMinute[timestamp] = entry; newDamage = true; } } } } return(newDamage); }
private static void SearchChunk(IEnumerable <string> chunk, ReadMemoryResults res, bool readChatMessages = true, bool readLogMessages = true) { List <int> stamps = TimestampManager.getLatestStamps(3, ignoreStamp); foreach (string it in chunk) { string logMessage = it; string t = logMessage.Substring(0, 5); int hour = int.Parse(logMessage.Substring(0, 2)); int minute = int.Parse(logMessage.Substring(3, 2)); if (!stamps.Contains(TimestampManager.getStamp(hour, minute))) { continue; // the log message is not recent, so we skip parsing it } if (flashClient) { // there is some inconsistency with log messages, certain log messages use "12:00: Message.", others use "12:00 Message" // if there is a : after the timestamp we remove it if (logMessage[5] == ':') { logMessage = logMessage.Remove(5, 1); } } string message = logMessage.Substring(6); // message without timestamp if (readLogMessages) { if (logMessage.Length > 14 && logMessage.Substring(5, 9) == " You see ") { // the message contains "you see", so it's a look message if (!res.lookMessages.ContainsKey(t)) { res.lookMessages.Add(t, new List <string>()); } res.lookMessages[t].Add(logMessage); continue; } else if (message.Contains(':')) { if (logMessage.Length > 14 && logMessage.Substring(5, 9) == " Loot of ") // loot drop message { if (!res.itemDrops.ContainsKey(t)) { res.itemDrops.Add(t, new List <string>()); } res.itemDrops[t].Add(logMessage); continue; } } else if (logMessage.Length > 17 && logMessage.Substring(5, 12) == " You gained ") { // the message is an experience string, "You gained x experience." try { int experience = int.Parse(logMessage.Substring(17).Split(' ')[0]); if (!res.exp.ContainsKey(t)) { res.exp.Add(t, experience); } else { res.exp[t] = res.exp[t] + experience; } } catch { } continue; } else if (logMessage.Length == 19 && logMessage.Substring(5, 14) == " You are dead.") { if (!res.deaths.ContainsKey(t)) { res.deaths.Add(t, true); } } else if (logMessage.Length > 18) { string[] split = message.Split(' '); int index = split.IndexOf("hitpoints"); if (index > 0) { int ind; // damage log message (X loses Y hitpoints due to an attack by Z.) int damage = 0; if (!int.TryParse(split[index - 1], out damage)) { continue; } string player; if (logMessage.Substring(logMessage.Length - 12) == "your attack.") { // X lost Y hitpoints because of your attack. // attacker is the player himself player = "You"; } else if (split.Contains("by")) { // X lost Y hitpoints because of an attack by Z. // Z is the attacker => after the word "by" player = ""; ind = split.IndexOf("by") + 1; for (int i = ind; i < split.Length; i++) { player = (player == "" ? player : player + " ") + split[i]; } } else { continue; } string splitTerm; if (split.Contains("loses")) { splitTerm = "loses"; } else if (split.Contains("lose")) { splitTerm = "lose"; } else { continue; } ind = split.IndexOf(splitTerm); string target = ""; for (int i = 0; i < ind; i++) { target = (target == "" ? target : target + " ") + split[i]; } if (!res.damageDealt.ContainsKey(player)) { res.damageDealt.Add(player, new Dictionary <string, DamageEntry>()); } DamageEntry damageEntry; if (!res.damageDealt[player].ContainsKey(t)) { damageEntry = new DamageEntry(); damageEntry.damage = damage; damageEntry.targetDamage.Add(target, damage); res.damageDealt[player].Add(t, damageEntry); } else { damageEntry = res.damageDealt[player][t]; damageEntry.damage += damage; if (damageEntry.targetDamage.ContainsKey(target)) { damageEntry.targetDamage[target] += damage; } else { damageEntry.targetDamage.Add(target, damage); } } continue; } else { index = split.IndexOf("hitpoints."); if (index > 0) { // heal log message (X healed Y for Z hitpoints.) int healing = 0; if (!int.TryParse(split[index - 1], out healing)) { continue; } int forIndex = split.IndexOf("for"); if (forIndex <= 0) { continue; } string splitTerm; if (split.Contains("heal")) { splitTerm = "heal"; } else if (split.Contains("healed")) { splitTerm = "healed"; } else { continue; } int healIndex = split.IndexOf(splitTerm); if (healIndex >= forIndex) { continue; } string source = ""; for (int i = 0; i < healIndex; i++) { if (split[i] == "was" || split[i] == "were") { break; } if (split[i] == "by") { continue; } source = (source == "" ? source : source + " ") + split[i]; } string target = ""; for (int i = healIndex + 1; i < forIndex; i++) { if (split[i] == "was" || split[i] == "were") { break; } if (split[i] == "by") { continue; } target = (target == "" ? target : target + " ") + split[i]; } if (target == "yourself" || target == "itself" || target == "himself" || target == "herself") { target = source; } if (target.Length == 0 || source.Length == 0) { continue; } if (split.Contains("by")) { // X healed Y for Z. => X is the source and Y is the target (default) // X was healed by Y for Z. => X is the target and Y is the source, so swap source and target string temp = source; source = target; target = temp; } if (!res.healingDone.ContainsKey(source)) { res.healingDone.Add(source, new Dictionary <string, DamageEntry>()); } DamageEntry healingEntry; if (!res.healingDone[source].ContainsKey(t)) { healingEntry = new DamageEntry(); healingEntry.damage = healing; healingEntry.targetDamage.Add(target, healing); res.healingDone[source].Add(t, healingEntry); } else { healingEntry = res.healingDone[source][t]; healingEntry.damage += healing; if (healingEntry.targetDamage.ContainsKey(target)) { healingEntry.targetDamage[target] += healing; } else { healingEntry.targetDamage.Add(target, healing); } } } else if (logMessage.Substring(5, 14) == " You advanced " && logMessage.Contains("level", StringComparison.OrdinalIgnoreCase)) { // advancement log message (You advanced from level x to level x + 1.) if (logMessage[logMessage.Length - 1] == '.') { if (GlobalDataManager.AddLevelAdvance(logMessage)) { res.newAdvances.Add(logMessage); } continue; } } else if (logMessage.Substring(5, 7) == " Using " && logMessage.Substring(logMessage.Length - 3, 3) == "...") { // using log message (Using one of X items...) var values = Parser.ParseUsingMessage(logMessage); if (!res.usingMessages.ContainsKey(values.Item1)) { res.usingMessages.Add(values.Item1, new Dictionary <string, HashSet <int> >()); } if (!res.usingMessages[values.Item1].ContainsKey(t)) { res.usingMessages[values.Item1].Add(t, new HashSet <int>()); } res.usingMessages[values.Item1][t].Add(values.Item2); continue; } else { foreach (Event ev in StorageManager.eventIdMap.Values) { foreach (string evMessage in ev.eventMessages) { if (logMessage.Length == evMessage.Length + 6 && logMessage.Contains(evMessage.Trim(), StringComparison.OrdinalIgnoreCase)) { res.eventMessages.Add(new Tuple <Event, string>(ev, logMessage)); } } } } } } } if (readChatMessages) { if (message.Contains(':')) { if (logMessage.Length > 14 && logMessage.Substring(5, 9) == " Loot of ") // loot drop message { continue; } else // if the message contains the ':' symbol but is not a loot drop message, it is a chat message, i.e. a command or url // we only split at most once, because the chat message can contain the ':' symbol as well and we don't want to discard that { string[] split = message.Split(new char[] { ':' }, 2); string command = split[1]; // now get the player name, we have to discard the level that is between brackets // players can also have spaces in their name, so we take that into account string[] playersplit = split[0].Split(' '); string player = ""; foreach (string str in playersplit) { if (str.Contains('[')) { break; } player = (player == "" ? player : player + " ") + str; } if (player == "http" || player == "https") { continue; // I don't remember why we do this, possible http link in a log message? not sure } if (command.Contains('@')) { // @ symbol symbolizes a command, so if there is an @ symbol, we treat the string as a command if (!res.commands.ContainsKey(t)) { res.commands.Add(t, new List <Tuple <string, string> >()); } res.commands[t].Add(new Tuple <string, string>(player, command)); } else if (command.Contains("www") || command.Contains("http") || command.Contains(".com") || command.Contains(".net") || command.Contains(".tv") || command.Contains(".br")) { // check if the command is an url, we aren't really smart about this, just check for a couple of common url-like things if (!res.urls.ContainsKey(t)) { res.urls.Add(t, new List <Tuple <string, string> >()); } res.urls[t].Add(new Tuple <string, string>(player, command)); } } } } } }
private static void SearchChunk(IEnumerable<string> chunk, ReadMemoryResults res, bool readChatMessages = true, bool readLogMessages = true) { List<int> stamps = TimestampManager.getLatestStamps(3, ignoreStamp); foreach (string it in chunk) { string logMessage = it; string t = logMessage.Substring(0, 5); int hour = int.Parse(logMessage.Substring(0, 2)); int minute = int.Parse(logMessage.Substring(3, 2)); if (!stamps.Contains(TimestampManager.getStamp(hour, minute))) continue; // the log message is not recent, so we skip parsing it if (FlashClient) { // there is some inconsistency with log messages, certain log messages use "12:00: Message.", others use "12:00 Message" // if there is a : after the timestamp we remove it if (logMessage[5] == ':') { logMessage = logMessage.Remove(5, 1); } } logMessage = logMessage.Replace(" (active prey bonus)", ""); string message = logMessage.Substring(6); // message without timestamp if (readLogMessages) { if (logMessage.Length > 14 && logMessage.Substring(5, 9) == " You see " && logMessage[logMessage.Length - 1] == '.') { // the message contains "you see", so it's a look message if (!res.lookMessages.ContainsKey(t)) res.lookMessages.Add(t, new List<string>()); if (!skipDuplicateCommands || !res.lookMessages[t].Contains(logMessage)) { res.lookMessages[t].Add(logMessage); } continue; } else if (message.Contains(':')) { if (logMessage.Length > 14 && logMessage.Substring(5, 9) == " Loot of ") { // loot drop message if (!res.itemDrops.ContainsKey(t)) res.itemDrops.Add(t, new List<string>()); res.itemDrops[t].Add(logMessage); continue; } } else if (logMessage.Length > 17 && logMessage.Substring(5, 12) == " You gained " && logMessage.EndsWith("experience points.")) { // the message is an experience string, "You gained x experience." try { int experience = int.Parse(logMessage.Substring(17).Split(' ')[0]); if (!res.exp.ContainsKey(t)) res.exp.Add(t, experience); else res.exp[t] = res.exp[t] + experience; } catch { } continue; } else if (logMessage.Length == 19 && logMessage.Substring(5, 14) == " You are dead.") { if (!res.deaths.ContainsKey(t)) res.deaths.Add(t, true); } else if (logMessage.Length > 18) { string[] split = message.Split(' '); int index = split.IndexOf("hitpoints"); if (index > 0) { int ind; // damage log message (X loses Y hitpoints due to an attack by Z.) int damage = 0; if (!int.TryParse(split[index - 1], out damage)) { continue; } string player; if ((logMessage.Substring(logMessage.Length - 12) == "your attack.") || (logMessage.Substring(logMessage.Length - 21) == "your critical attack.")) { // X lost Y hitpoints because of your attack. // attacker is the player himself player = "You"; } else if (split.Contains("by")) { // X lost Y hitpoints because of an attack by Z. // Z is the attacker => after the word "by" player = ""; ind = split.IndexOf("by") + 1; for (int i = ind; i < split.Length; i++) { player = (player == "" ? player : player + " ") + split[i]; } } else { continue; } string splitTerm; if (split.Contains("loses")) { splitTerm = "loses"; } else if (split.Contains("lose")) { splitTerm = "lose"; } else { continue; } ind = split.IndexOf(splitTerm); string target = ""; for (int i = 0; i < ind; i++) { target = (target == "" ? target : target + " ") + split[i]; } if (!res.damageDealt.ContainsKey(player)) { res.damageDealt.Add(player, new Dictionary<string, DamageEntry>()); } DamageEntry damageEntry; if (!res.damageDealt[player].ContainsKey(t)) { damageEntry = new DamageEntry(); damageEntry.damage = damage; damageEntry.targetDamage.Add(target, damage); res.damageDealt[player].Add(t, damageEntry); } else { damageEntry = res.damageDealt[player][t]; damageEntry.damage += damage; if (damageEntry.targetDamage.ContainsKey(target)) { damageEntry.targetDamage[target] += damage; } else { damageEntry.targetDamage.Add(target, damage); } } continue; } else { index = split.IndexOf("hitpoints."); if (index > 0) { // heal log message (X healed Y for Z hitpoints.) int healing = 0; if (!int.TryParse(split[index - 1], out healing)) { continue; } int forIndex = split.IndexOf("for"); if (forIndex <= 0) { continue; } string splitTerm; if (split.Contains("heal")) { splitTerm = "heal"; } else if (split.Contains("healed")) { splitTerm = "healed"; } else { continue; } int healIndex = split.IndexOf(splitTerm); if (healIndex >= forIndex) { continue; } string source = ""; for (int i = 0; i < healIndex; i++) { if (split[i] == "was" || split[i] == "were") break; if (split[i] == "by") continue; source = (source == "" ? source : source + " ") + split[i]; } string target = ""; for (int i = healIndex + 1; i < forIndex; i++) { if (split[i] == "was" || split[i] == "were") break; if (split[i] == "by") continue; target = (target == "" ? target : target + " ") + split[i]; } if (target == "yourself" || target == "itself" || target == "himself" || target == "herself") { target = source; } if (target.Length == 0 || source.Length == 0) { continue; } if (split.Contains("by")) { // X healed Y for Z. => X is the source and Y is the target (default) // X was healed by Y for Z. => X is the target and Y is the source, so swap source and target string temp = source; source = target; target = temp; } if (!res.healingDone.ContainsKey(source)) { res.healingDone.Add(source, new Dictionary<string, DamageEntry>()); } DamageEntry healingEntry; if (!res.healingDone[source].ContainsKey(t)) { healingEntry = new DamageEntry(); healingEntry.damage = healing; healingEntry.targetDamage.Add(target, healing); res.healingDone[source].Add(t, healingEntry); } else { healingEntry = res.healingDone[source][t]; healingEntry.damage += healing; if (healingEntry.targetDamage.ContainsKey(target)) { healingEntry.targetDamage[target] += healing; } else { healingEntry.targetDamage.Add(target, healing); } } } else if (logMessage.Substring(5, 14) == " You advanced " && logMessage.Contains("level", StringComparison.OrdinalIgnoreCase)) { // advancement log message (You advanced from level x to level x + 1.) if (logMessage[logMessage.Length - 1] == '.') { if (GlobalDataManager.AddLevelAdvance(logMessage)) { res.newAdvances.Add(logMessage); } continue; } } else if (logMessage.Substring(5, 7) == " Using " && logMessage.Substring(logMessage.Length - 3, 3) == "...") { // using log message (Using one of X items...) var values = Parser.ParseUsingMessage(logMessage); if (!res.usingMessages.ContainsKey(values.Item1)) res.usingMessages.Add(values.Item1, new Dictionary<string, HashSet<int>>()); if (!res.usingMessages[values.Item1].ContainsKey(t)) res.usingMessages[values.Item1].Add(t, new HashSet<int>()); res.usingMessages[values.Item1][t].Add(values.Item2); continue; } else if (logMessage.Length > 50 && logMessage.Substring(5, 45) == " Congratulations! You earned the achievement ") { Achievement achievement = StorageManager.getAchievement(Parser.GetAchievement(logMessage)); if (achievement != null) { res.achievements.Add(new Tuple<Achievement, string>(achievement, logMessage)); } else { Console.WriteLine("Unrecognized achievement {0}.", Parser.GetAchievement(logMessage)); } } else { foreach (Event ev in StorageManager.eventIdMap.Values) { foreach (string evMessage in ev.eventMessages) { if (logMessage.Length == evMessage.Length + 6 && logMessage.Contains(evMessage.Trim(), StringComparison.OrdinalIgnoreCase)) { res.eventMessages.Add(new Tuple<Event, string>(ev, logMessage)); } } } } } } } if (readChatMessages) { if (message.Contains(':')) { if (logMessage.Length > 14 && logMessage.Substring(5, 9) == " Loot of ") { // loot drop message continue; } else { // if the message contains the ':' symbol but is not a loot drop message, it is a chat message, i.e. a command or url // we only split at most once, because the chat message can contain the ':' symbol as well and we don't want to discard that string[] split = message.Split(new char[] { ':' }, 2); string command = split[1]; // now get the player name, we have to discard the level that is between brackets // players can also have spaces in their name, so we take that into account string[] playersplit = split[0].Split(' '); string player = ""; foreach (string str in playersplit) { if (str.Contains('[')) break; player = (player == "" ? player : player + " ") + str; } if (player == "http" || player == "https") continue; // I don't remember why we do this, possible http link in a log message? not sure if (command.Contains('@')) { // @ symbol symbolizes a command, so if there is an @ symbol, we treat the string as a command if (!res.commands.ContainsKey(t)) res.commands.Add(t, new List<Tuple<string, string>>()); var tpl = new Tuple<string, string>(player, command); if (!skipDuplicateCommands || !res.commands[t].Contains(tpl)) { res.commands[t].Add(tpl); } } else if (command.Contains("www") || command.Contains("http") || command.Contains(".com") || command.Contains(".net") || command.Contains(".tv") || command.Contains(".br")) { // check if the command is an url, we aren't really smart about this, just check for a couple of common url-like things if (!res.urls.ContainsKey(t)) res.urls.Add(t, new List<Tuple<string, string>>()); res.urls[t].Add(new Tuple<string, string>(player, command)); } } } } } }