private void AssignAgentMasters(ParsedLog log, LogProcessorState state) { // Requires aware times to be set first Debug.Assert(state.AwareTimesSet); Debug.Assert(!state.MastersAssigned); Debug.Assert(state.AgentsByAddress != null); Debug.Assert(state.AgentsById != null); foreach (var combatItem in log.ParsedCombatItems) { if (combatItem.IsStateChange == StateChange.Normal) { if (combatItem.SrcMasterId != 0) { Agent minion = null; if (state.AgentsById.TryGetValue(combatItem.SrcAgentId, out var agentsWithId)) { foreach (var agent in agentsWithId) { if (agent.IsWithinAwareTime(combatItem.Time)) { minion = agent; break; } } } if (minion != null && minion.Master == null) { Agent master = null; if (state.AgentsById.TryGetValue(combatItem.SrcMasterId, out var potentialMasters)) { foreach (var agent in potentialMasters) { if (!(agent is Gadget) && agent.IsWithinAwareTime(combatItem.Time)) { master = agent; break; } } } if (master != null) { bool inCycle = false; var masterParent = master; while (masterParent != null) { if (masterParent == minion) { // A cycle is present in the minion hierarchy, this minion would end up as // a transitive minion of itself, which could cause infinite looping. // This is common in very old logs where minion data is somewhat weird. inCycle = true; break; } masterParent = masterParent.Master; } if (!inCycle) { minion.Master = master; master.MinionList.Add(minion); } } } } } if (combatItem.IsStateChange == StateChange.AttackTarget) { ulong attackTargetAddress = combatItem.SrcAgent; ulong masterGadgetAddress = combatItem.DstAgent; AttackTarget target = null; Gadget master = null; foreach (var agent in state.Agents) { switch (agent) { case Gadget gadget when gadget.AgentOrigin.OriginalAgentData.Any(x => x.Address == masterGadgetAddress): master = gadget; break; case AttackTarget attackTarget when attackTarget.AgentOrigin.OriginalAgentData.Any(x => x.Address == attackTargetAddress): target = attackTarget; break; } } if (master != null && target != null) { master.AddAttackTarget(target); target.Gadget = master; } } } state.MastersAssigned = true; }
// Requires aware times to be set first private void AssignAgentMasters(ParsedLog log, IReadOnlyCollection <Agent> agents) { foreach (var combatItem in log.ParsedCombatItems) { if (combatItem.IsStateChange == StateChange.Normal) { if (combatItem.SrcMasterId != 0) { Agent minion = null; // TODO: Look up by id with a dictionary first foreach (var agent in agents) { if (agent.Id == combatItem.SrcAgentId && agent.IsWithinAwareTime(combatItem.Time)) { minion = agent; break; } } if (minion != null && minion.Master == null) { Agent master = null; foreach (var agent in agents) { if (!(agent is Gadget) && agent.Id == combatItem.SrcMasterId && agent.IsWithinAwareTime(combatItem.Time)) { master = agent; break; } } if (master != null) { bool inCycle = false; var masterParent = master; while (masterParent != null) { if (masterParent == minion) { // A cycle is present in the minion hierarchy, this minion would end up as // a transitive minion of itself, which could cause infinite looping. // This is common in very old logs where minion data is somewhat weird. inCycle = true; break; } masterParent = masterParent.Master; } if (!inCycle) { minion.Master = master; master.MinionList.Add(minion); } } } } } if (combatItem.IsStateChange == StateChange.AttackTarget) { ulong attackTargetAddress = combatItem.SrcAgent; ulong masterGadgetAddress = combatItem.DstAgent; AttackTarget target = null; Gadget master = null; foreach (var agent in agents) { switch (agent) { case Gadget gadget when gadget.Address == masterGadgetAddress: master = gadget; break; case AttackTarget attackTarget when attackTarget.Address == attackTargetAddress: target = attackTarget; break; } } if (master != null && target != null) { master.AddAttackTarget(target); target.Gadget = master; } } } }