internal static SpellCountData GetSpellCounts(List <string> playerList, PlayerStats raidStats) { var result = new SpellCountData(); HashSet <TimedAction> castsDuring = new HashSet <TimedAction>(); HashSet <TimedAction> receivedDuring = new HashSet <TimedAction>(); QuerySpellBlocks(raidStats, castsDuring, receivedDuring); foreach (var action in castsDuring.AsParallel().Where(cast => playerList.Contains((cast as SpellCast).Caster))) { SpellCast cast = action as SpellCast; if (cast.SpellData != null) { UpdateMaps(cast.SpellData, cast.Caster, result.PlayerCastCounts, result.PlayerInterruptedCounts, result.MaxCastCounts, result.UniqueSpells, cast.Interrupted); } } foreach (var action in receivedDuring.AsParallel().Where(received => playerList.Contains((received as ReceivedSpell).Receiver))) { ReceivedSpell received = action as ReceivedSpell; // dont include detrimental received spells since they're mostly things like being nuked if (received.SpellData != null && received.SpellData.IsBeneficial) { UpdateMaps(received.SpellData, received.Receiver, result.PlayerReceivedCounts, null, result.MaxReceivedCounts, result.UniqueSpells); } } return(result); }
internal static SpellCountData GetSpellCounts(List <string> playerList, PlayerStats raidStats) { var result = new SpellCountData(); HashSet <IAction> castsDuring = new HashSet <IAction>(); HashSet <IAction> receivedDuring = new HashSet <IAction>(); double maxTime = -1; raidStats.Ranges.TimeSegments.ForEach(segment => { maxTime = maxTime == -1 ? segment.BeginTime + raidStats.TotalSeconds : maxTime; var blocks = DataManager.Instance.GetCastsDuring(segment.BeginTime - COUNT_OFFSET, segment.EndTime); blocks.ForEach(block => { if (raidStats.MaxTime == raidStats.TotalSeconds || block.BeginTime <= maxTime) { block.Actions.ForEach(action => castsDuring.Add(action)); } }); blocks = DataManager.Instance.GetReceivedSpellsDuring(segment.BeginTime - COUNT_OFFSET, segment.EndTime); blocks.ForEach(block => { if (raidStats.MaxTime == raidStats.TotalSeconds || block.BeginTime <= maxTime) { block.Actions.ForEach(action => receivedDuring.Add(action)); } }); }); foreach (var action in castsDuring.AsParallel().Where(cast => playerList.Contains((cast as SpellCast).Caster))) { SpellCast cast = action as SpellCast; var spellData = DataManager.Instance.GetSpellByAbbrv(DataManager.Instance.AbbreviateSpellName(cast.Spell)); if (spellData != null) { UpdateMaps(spellData, cast.Caster, result.PlayerCastCounts, result.MaxCastCounts, result.UniqueSpells); } } foreach (var action in receivedDuring.AsParallel().Where(received => playerList.Contains((received as ReceivedSpell).Receiver))) { ReceivedSpell received = action as ReceivedSpell; var spellData = received.SpellData; if (spellData == null && received.Ambiguity.Count > 0 && DataManager.ResolveSpellAmbiguity(received, out SpellData replaced)) { spellData = replaced; } // dont include detrimental received spells since they're mostly things like being nuked if (spellData != null && spellData.IsBeneficial) { UpdateMaps(spellData, received.Receiver, result.PlayerReceivedCounts, result.MaxReceivedCounts, result.UniqueSpells); } } return(result); }
internal static bool ResolveSpellAmbiguity(ReceivedSpell spell, out SpellData replaced) { replaced = null; if (spell.Ambiguity.Count < 30) { int spellClass = (int)PlayerManager.Instance.GetPlayerClassEnum(spell.Receiver); var subset = spell.Ambiguity.FindAll(test => test.Target == (int)SpellTarget.SELF && spellClass != 0 && (test.ClassMask & spellClass) == spellClass); var distinct = subset.Distinct(AbbrvComparer).ToList(); replaced = distinct.Count == 1 ? distinct.First() : spell.Ambiguity.First(); } return(replaced != null); }
private const int SPELL_TIME_OFFSET = 10; // seconds back internal static SpellCountData GetSpellCounts(List <string> playerList, PlayerStats raidStats) { var result = new SpellCountData(); var offsets = GetOffsetTimes(raidStats); var begins = offsets.Item1; var lasts = offsets.Item2; List <IAction> castsDuring = new List <IAction>(); List <IAction> receivedDuring = new List <IAction>(); for (int i = 0; i < begins.Count; i++) { var blocks = DataManager.Instance.GetCastsDuring(begins[i], lasts[i]); blocks.ForEach(block => castsDuring.AddRange(block.Actions)); blocks = DataManager.Instance.GetReceivedSpellsDuring(begins[i], lasts[i]); blocks.ForEach(block => receivedDuring.AddRange(block.Actions)); } foreach (var action in castsDuring.AsParallel().Where(cast => playerList.Contains((cast as SpellCast).Caster))) { SpellCast cast = action as SpellCast; var spellData = DataManager.Instance.GetSpellByAbbrv(Helpers.AbbreviateSpellName(cast.Spell)); if (spellData != null) { UpdateMaps(spellData, cast.Caster, result.PlayerCastCounts, result.MaxCastCounts, result.UniqueSpells); } } foreach (var action in receivedDuring.AsParallel().Where(received => playerList.Contains((received as ReceivedSpell).Receiver))) { ReceivedSpell received = action as ReceivedSpell; var spellData = received.SpellData; var spellClass = PlayerManager.Instance.GetPlayerClassEnum(received.Receiver); if (DataManager.Instance.CheckForSpellAmbiguity(spellData, spellClass, out SpellData replaced)) { spellData = replaced; } UpdateMaps(spellData, received.Receiver, result.PlayerReceivedCounts, result.MaxReceivedCounts, result.UniqueSpells); } return(result); }
private bool IsValid(ReceivedSpell spell, Dictionary <string, byte> uniqueNames, string player, out SpellData replaced) { bool valid = false; replaced = spell.SpellData; if (!string.IsNullOrEmpty(player) && uniqueNames.ContainsKey(player)) { SpellData spellData = spell.SpellData ?? null; if (spellData == null && spell.Ambiguity.Count > 0 && DataManager.ResolveSpellAmbiguity(spell, out replaced)) { spellData = replaced; } if (spellData != null) { valid = !spellData.IsProc && (CurrentShowSelfOnly || (spell is SpellCast || !string.IsNullOrEmpty(spellData.LandsOnOther))); valid = valid && (CurrentSpellType == 0 || CurrentSpellType == 1 && spellData.IsBeneficial || CurrentSpellType == 2 && !spellData.IsBeneficial); } } return(valid); }
internal void AddReceivedSpell(ReceivedSpell received, double beginTime) => Helpers.AddAction(AllReceivedSpellBlocks, received, beginTime);
public static void Process(LineData lineData) { bool handled = false; try { string[] split = lineData.Action.Split(' '); if (split != null && split.Length > 1 && !split[0].Contains(".")) { string player = null; string spellName = null; bool isYou = false; bool isSpell = false; bool isInterrupted = false; // [Sat Mar 14 19:57:48 2020] You activate Venon's Vindication. // [Mon Mar 02 19:46:09 2020] You begin casting Shield of Destiny Rk. II. // [Sat Mar 14 19:45:40 2020] You begin singing Agilmente's Aria of Eagles. // [Tue Dec 25 11:38:42 2018] You begin casting Focus of Arcanum VI. // [Sun Dec 02 16:33:37 2018] You begin singing Vainglorious Shout VI. // [Mon Mar 02 19:44:27 2020] Stabborz activates Conditioned Reflexes Rk. II. // [Mon Mar 02 19:47:43 2020] Sancus begins casting Burnout XIV Rk. II. // [Mon Mar 02 19:33:49 2020] Iggokk begins singing Shauri's Sonorous Clouding III. // [Tue Dec 25 09:58:20 2018] Sylfvia begins to cast a spell. <Syllable of Mending Rk. II> // [Tue Dec 25 14:19:57 2018] Sonozen begins to sing a song. <Lyre Leap> // [Thu Apr 18 01:38:10 2019] Incogitable's Dizzying Wheel Rk. II spell is interrupted. // [Thu Apr 18 01:38:00 2019] Your Stormjolt Vortex Rk. III spell is interrupted. // [Sun Mar 01 22:34:58 2020] You have entered The Eastern Wastes. if (split[0] == "You") { player = ConfigUtil.PlayerName; isYou = true; if (split[1] == "activate") { spellName = ParseNewSpellName(split, 2); } // ZONE EVENT - moved here to keep it in the same thread as lands on message parsing if (split[1] == "have" && split[2] == "entered") { string zone = string.Join(" ", split, 3, split.Length - 3).TrimEnd('.'); DataManager.Instance.AddMiscRecord(new ZoneRecord { Zone = zone }, DateUtil.ParseLogDate(lineData.Line, out _)); handled = true; if (!zone.StartsWith("an area", StringComparison.OrdinalIgnoreCase)) { DataManager.Instance.ZoneChanged(); } } else if (split[1] == "begin") { if (split[2] == "casting") { spellName = ParseNewSpellName(split, 3); isSpell = true; } else if (split[2] == "singing") { spellName = ParseNewSpellName(split, 3); } } } else if (split[1] == "activates") { player = split[0]; spellName = ParseNewSpellName(split, 2); } else if (split[1] == "begins") { if (split[2] == "casting") { player = split[0]; spellName = ParseNewSpellName(split, 3); isSpell = true; } else if (split[2] == "singing") { player = split[0]; spellName = ParseNewSpellName(split, 3); } else if (split.Length > 5 && split[2] == "to" && split[4] == "a") { if (split[3] == "cast" && split[5] == "spell.") { player = split[0]; spellName = ParseOldSpellName(split, 6); isSpell = true; } else if (split[3] == "sing" && split[5] == "song.") { player = split[0]; spellName = ParseOldSpellName(split, 6); } } } else if (split.Length > 4 && split[split.Length - 1] == "interrupted." && split[split.Length - 2] == "is" && split[split.Length - 3] == "spell") { isInterrupted = true; spellName = string.Join(" ", split, 1, split.Length - 4); if (split[0] == "Your") { player = ConfigUtil.PlayerName; } else if (split[0].Length > 3 && split[0][split[0].Length - 1] == 's' && split[0][split[0].Length - 2] == '\'') { player = split[0].Substring(0, split[0].Length - 2); } } if (!handled && !string.IsNullOrEmpty(player) && !string.IsNullOrEmpty(spellName)) { double currentTime = DateUtil.ParseDate(lineData.Line.Substring(1, 24)); if (!isInterrupted) { if (isSpell && isYou) { // For some reason Glyphs don't show up for current player CheckForSpecial(SpecialYouCodes, spellName, player, currentTime); } var spellData = DataManager.Instance.GetSpellByName(spellName); DataManager.Instance.AddSpellCast(new SpellCast { Caster = player, Spell = string.Intern(spellName), SpellData = spellData, BeginTime = currentTime }, currentTime); } else { DataManager.Instance.HandleSpellInterrupt(player, spellName, currentTime); } handled = true; } if (!handled && lineData.Line[lineData.Line.Length - 1] != ')') { if (split[0].Length > 3 && split[0][split[0].Length - 1] == 's' && split[0][split[0].Length - 2] == '\'') { player = string.Intern(split[0].Substring(0, split[0].Length - 2)); var landsOnPosessiveMessage = string.Join(" ", split, 1, split.Length - 1); List <SpellData> result = DataManager.Instance.GetPosessiveLandsOnOther(player, landsOnPosessiveMessage, out _); if (result != null) { double currentTime = DateUtil.ParseDate(lineData.Line.Substring(1, 24)); var newSpell = new ReceivedSpell { Receiver = player, BeginTime = currentTime }; if (result.Count == 1) { newSpell.SpellData = result.First(); CheckForSpecial(SpecialLandsOnCodes, newSpell.SpellData.Name, newSpell.Receiver, currentTime); } else { newSpell.Ambiguity.AddRange(result); } // valid lands on other. check for pet receiving DPS AA if (PetCheck.ContainsKey(landsOnPosessiveMessage)) { PlayerManager.Instance.AddVerifiedPet(player); } DataManager.Instance.AddReceivedSpell(newSpell, currentTime); handled = true; } } else if (split.Length > 0) { string landsOnMessage = string.Join(" ", split, 1, split.Length - 1); int midPeriod = -1; // some abilities like staunch show a lands on message followed by a heal. so search based on first sentence if (landsOnMessage.Length >= 2) { if ((midPeriod = landsOnMessage.LastIndexOf('.', landsOnMessage.Length - 2)) > -1) { landsOnMessage = landsOnMessage.Substring(0, midPeriod + 1); } } player = split[0]; List <SpellData> result = DataManager.Instance.GetNonPosessiveLandsOnOther(player, landsOnMessage, out _); if (result == null) { result = DataManager.Instance.GetLandsOnYou(player, player + " " + landsOnMessage, out _); if (result != null) { player = ConfigUtil.PlayerName; } } else { // valid lands on other. check for pet receiving DPS AA if (PetCheck.ContainsKey(landsOnMessage)) { PlayerManager.Instance.AddVerifiedPet(player); } } if (result != null) { double currentTime = DateUtil.ParseDate(lineData.Line.Substring(1, 24)); var newSpell = new ReceivedSpell() { Receiver = string.Intern(player), BeginTime = currentTime }; if (result.Count == 1) { newSpell.SpellData = result.First(); CheckForSpecial(SpecialLandsOnCodes, newSpell.SpellData.Name, newSpell.Receiver, currentTime); } else { newSpell.Ambiguity.AddRange(result); } DataManager.Instance.AddReceivedSpell(newSpell, currentTime); handled = true; } } } } } catch (Exception e) { LOG.Error(e); } DebugUtil.UnregisterLine(lineData.LineNumber, handled); }
public static void Process(LineData lineData) { try { string[] split = lineData.Action.Split(' '); if (split != null && split.Length > 2 && !split[0].Contains(".")) { string player = null; string spellName = null; bool isYou = false; bool isSpell = false; bool isInterrupted = false; bool handled = false; // [Sat Mar 14 19:57:48 2020] You activate Venon's Vindication. // [Mon Mar 02 19:46:09 2020] You begin casting Shield of Destiny Rk. II. // [Sat Mar 14 19:45:40 2020] You begin singing Agilmente's Aria of Eagles. // [Tue Dec 25 11:38:42 2018] You begin casting Focus of Arcanum VI. // [Sun Dec 02 16:33:37 2018] You begin singing Vainglorious Shout VI. // [Mon Mar 02 19:44:27 2020] Stabborz activates Conditioned Reflexes Rk. II. // [Mon Mar 02 19:47:43 2020] Sancus begins casting Burnout XIV Rk. II. // [Mon Mar 02 19:33:49 2020] Iggokk begins singing Shauri's Sonorous Clouding III. // [Tue Dec 25 09:58:20 2018] Sylfvia begins to cast a spell. <Syllable of Mending Rk. II> // [Tue Dec 25 14:19:57 2018] Sonozen begins to sing a song. <Lyre Leap> // [Thu Apr 18 01:38:10 2019] Incogitable's Dizzying Wheel Rk. II spell is interrupted. // [Thu Apr 18 01:38:00 2019] Your Stormjolt Vortex Rk. III spell is interrupted. if (split[0] == "You") { player = ConfigUtil.PlayerName; isYou = true; if (split[1] == "activate") { spellName = ParseNewSpellName(split, 2); } else if (split[1] == "begin") { if (split[2] == "casting") { spellName = ParseNewSpellName(split, 3); isSpell = true; } else if (split[2] == "singing") { spellName = ParseNewSpellName(split, 3); } } } else if (split[1] == "activates") { player = split[0]; spellName = ParseNewSpellName(split, 2); } else if (split[1] == "begins") { if (split[2] == "casting") { player = split[0]; spellName = ParseNewSpellName(split, 3); isSpell = true; } else if (split[2] == "singing") { player = split[0]; spellName = ParseNewSpellName(split, 3); } else if (split.Length > 5 && split[2] == "to" && split[4] == "a") { if (split[3] == "cast" && split[5] == "spell.") { player = split[0]; spellName = ParseOldSpellName(split, 6); isSpell = true; } else if (split[3] == "sing" && split[5] == "song.") { player = split[0]; spellName = ParseOldSpellName(split, 6); } } } else if (split.Length > 4 && split[split.Length - 1] == "interrupted." && split[split.Length - 2] == "is" && split[split.Length - 3] == "spell") { isInterrupted = true; spellName = string.Join(" ", split, 1, split.Length - 4); if (split[0] == "Your") { player = ConfigUtil.PlayerName; } else if (split[0].Length > 3 && split[0][split[0].Length - 1] == 's' && split[0][split[0].Length - 2] == '\'') { player = split[0].Substring(0, split[0].Length - 2); } } if (!string.IsNullOrEmpty(player) && !string.IsNullOrEmpty(spellName)) { double currentTime = DateUtil.ParseDate(lineData.Line.Substring(1, 24)); if (!isInterrupted) { if (isSpell && isYou) { // For some reason Glyphs don't show up for current player CheckForSpecial(SpecialYouCodes, spellName, player, currentTime); } else if (isSpell && !isYou) { // Some spells only show up as casting CheckForSpecial(SpecialOtherCodes, spellName, player, currentTime); } DataManager.Instance.AddSpellCast(new SpellCast() { Caster = player, Spell = string.Intern(spellName) }, currentTime); } else { DataManager.Instance.HandleSpellInterrupt(player, spellName, currentTime); } handled = true; } if (!handled && lineData.Line[lineData.Line.Length - 1] != ')') { if (split[0].Length > 3 && split[0][split[0].Length - 1] == 's' && split[0][split[0].Length - 2] == '\'') { SpellData result = DataManager.Instance.GetPosessiveLandsOnOther(string.Join(" ", split, 1, split.Length - 1), out _); if (result != null) { double currentTime = DateUtil.ParseDate(lineData.Line.Substring(1, 24)); var newSpell = new ReceivedSpell() { Receiver = string.Intern(split[0].Substring(0, split[0].Length - 2)), SpellData = result }; DataManager.Instance.AddReceivedSpell(newSpell, currentTime); CheckForSpecial(SpecialLandsOnCodes, result.Name, newSpell.Receiver, currentTime); } } else { string landsOnMessage = string.Join(" ", split, 1, split.Length - 1); int midPeriod = -1; // some abilities like staunch show a lands on message followed by a heal. so search based on first sentence if ((midPeriod = landsOnMessage.LastIndexOf('.', landsOnMessage.Length - 2)) > -1) { landsOnMessage = landsOnMessage.Substring(0, midPeriod + 1); } player = split[0]; SpellData result = DataManager.Instance.GetNonPosessiveLandsOnOther(landsOnMessage, out _); if (result == null) { result = DataManager.Instance.GetLandsOnYou(player + " " + landsOnMessage, out _); if (result != null) { player = ConfigUtil.PlayerName; } } if (result != null) { double currentTime = DateUtil.ParseDate(lineData.Line.Substring(1, 24)); var newSpell = new ReceivedSpell() { Receiver = string.Intern(player), SpellData = result }; DataManager.Instance.AddReceivedSpell(newSpell, currentTime); CheckForSpecial(SpecialLandsOnCodes, result.Name, newSpell.Receiver, currentTime); } } } } } catch (ArgumentNullException ne) { LOG.Error(ne); } catch (NullReferenceException nr) { LOG.Error(nr); } catch (ArgumentOutOfRangeException aor) { LOG.Error(aor); } catch (ArgumentException ae) { LOG.Error(ae); } }