Beispiel #1
0
        private void SetAgentAwareTimes(LogProcessorState state)
        {
            foreach (var ev in state.Events)
            {
                if (ev is AgentEvent agentEvent)
                {
                    if (agentEvent.Agent == null)
                    {
                        continue;
                    }

                    if (agentEvent.Agent.FirstAwareTime == 0 || ev.Time < agentEvent.Agent.FirstAwareTime)
                    {
                        agentEvent.Agent.FirstAwareTime = ev.Time;
                    }

                    if (agentEvent.Agent.LastAwareTime == long.MaxValue || ev.Time > agentEvent.Agent.LastAwareTime)
                    {
                        agentEvent.Agent.LastAwareTime = ev.Time;
                    }
                }
                else if (ev is DamageEvent damageEvent)
                {
                    if (damageEvent.Attacker != null)
                    {
                        if (damageEvent.Attacker.FirstAwareTime == 0 || ev.Time < damageEvent.Attacker.FirstAwareTime)
                        {
                            damageEvent.Attacker.FirstAwareTime = ev.Time;
                        }

                        if (damageEvent.Attacker.LastAwareTime == long.MaxValue ||
                            ev.Time > damageEvent.Attacker.LastAwareTime)
                        {
                            damageEvent.Attacker.LastAwareTime = ev.Time;
                        }
                    }

                    if (damageEvent.Defender != null)
                    {
                        if (damageEvent.Defender.FirstAwareTime == 0 || ev.Time < damageEvent.Defender.FirstAwareTime)
                        {
                            damageEvent.Defender.FirstAwareTime = ev.Time;
                        }

                        if (damageEvent.Defender.LastAwareTime == long.MaxValue ||
                            ev.Time > damageEvent.Defender.LastAwareTime)
                        {
                            damageEvent.Defender.LastAwareTime = ev.Time;
                        }
                    }
                }
            }

            state.AwareTimesSet = true;
        }
Beispiel #2
0
        private Event GetEvent(LogProcessorState state,
                               IReadOnlyDictionary <uint, Skill> skillsById, ParsedCombatItem item)
        {
            Debug.Assert(state.AgentsByAddress != null);

            Agent GetAgentByAddress(ulong address)
            {
                if (state.AgentsByAddress.TryGetValue(address, out Agent agent))
                {
                    return(agent);
                }

                return(null);
            }

            Skill GetSkillById(uint id)
            {
                if (skillsById.TryGetValue(id, out Skill skill))
                {
                    return(skill);
                }

                return(null);
            }

            if (item.IsStateChange != StateChange.Normal)
            {
                switch (item.IsStateChange)
                {
                case StateChange.EnterCombat:
                    return(new AgentEnterCombatEvent(item.Time, GetAgentByAddress(item.SrcAgent),
                                                     (int)item.DstAgent));

                case StateChange.ExitCombat:
                    return(new AgentExitCombatEvent(item.Time, GetAgentByAddress(item.SrcAgent)));

                case StateChange.ChangeUp:
                    return(new AgentRevivedEvent(item.Time, GetAgentByAddress(item.SrcAgent)));

                case StateChange.ChangeDead:
                    return(new AgentDeadEvent(item.Time, GetAgentByAddress(item.SrcAgent)));

                case StateChange.ChangeDown:
                    return(new AgentDownedEvent(item.Time, GetAgentByAddress(item.SrcAgent)));

                case StateChange.Spawn:
                    return(new AgentSpawnEvent(item.Time, GetAgentByAddress(item.SrcAgent)));

                case StateChange.Despawn:
                    return(new AgentDespawnEvent(item.Time, GetAgentByAddress(item.SrcAgent)));

                case StateChange.HealthUpdate:
                    var healthFraction = item.DstAgent / 10000f;
                    return(new AgentHealthUpdateEvent(item.Time, GetAgentByAddress(item.SrcAgent),
                                                      healthFraction));

                case StateChange.WeaponSwap:
                    WeaponSet newWeaponSet;
                    switch (item.DstAgent)
                    {
                    case 0:
                        newWeaponSet = WeaponSet.Water1;
                        break;

                    case 1:
                        newWeaponSet = WeaponSet.Water2;
                        break;

                    case 4:
                        newWeaponSet = WeaponSet.Land1;
                        break;

                    case 5:
                        newWeaponSet = WeaponSet.Land2;
                        break;

                    default:
                        newWeaponSet = WeaponSet.Unknown;
                        break;
                    }

                    return(new AgentWeaponSwapEvent(item.Time, GetAgentByAddress(item.SrcAgent),
                                                    newWeaponSet));

                case StateChange.MaxHealthUpdate:
                    return(new AgentMaxHealthUpdateEvent(item.Time, GetAgentByAddress(item.SrcAgent),
                                                         item.DstAgent));

                case StateChange.Reward:
                    return(new RewardEvent(item.Time, item.DstAgent, item.Value));

                case StateChange.BuffInitial:
                    return(new InitialBuffEvent(item.Time, GetAgentByAddress(item.SrcAgent),
                                                GetSkillById(item.SkillId)));

                case StateChange.Position:
                {
                    float x = BitConversions.ToSingle((uint)(item.DstAgent & 0xFFFFFFFF));
                    float y = BitConversions.ToSingle((uint)(item.DstAgent >> 32 & 0xFFFFFFFF));
                    float z = BitConversions.ToSingle(item.Value);

                    return(new PositionChangeEvent(item.Time, GetAgentByAddress(item.SrcAgent), x, y, z));
                }

                case StateChange.Velocity:
                {
                    float x = BitConversions.ToSingle((uint)(item.DstAgent & 0xFFFFFFFF));
                    float y = BitConversions.ToSingle((uint)(item.DstAgent >> 32 & 0xFFFFFFFF));
                    float z = BitConversions.ToSingle(item.Value);

                    return(new VelocityChangeEvent(item.Time, GetAgentByAddress(item.SrcAgent), x, y, z));
                }

                case StateChange.Rotation:
                {
                    float x = BitConversions.ToSingle((uint)(item.DstAgent & 0xFFFFFFFF));
                    float y = BitConversions.ToSingle((uint)(item.DstAgent >> 32 & 0xFFFFFFFF));

                    return(new FacingChangeEvent(item.Time, GetAgentByAddress(item.SrcAgent), x, y));
                }

                case StateChange.TeamChange:
                    return(new TeamChangeEvent(item.Time, GetAgentByAddress(item.SrcAgent),
                                               item.DstAgent));

                case StateChange.Targetable:
                {
                    var agent = GetAgentByAddress(item.SrcAgent);
                    if (agent is AttackTarget target)
                    {
                        return(new TargetableChangeEvent(item.Time, target, item.DstAgent != 0));
                    }
                    else
                    {
                        return(new UnknownEvent(item.Time, item));
                    }
                }

                case StateChange.ReplInfo:
                    return(new UnknownEvent(item.Time, item));

                case StateChange.StackActive:
                    return(new ActiveBuffStackEvent(item.Time, GetAgentByAddress(item.SrcAgent),
                                                    (uint)item.DstAgent));

                case StateChange.StackReset:
                    return(new ResetBuffStackEvent(item.Time, GetAgentByAddress(item.SrcAgent), item.Padding,
                                                   item.Value));

                case StateChange.BreakbarState:
                    var breakbarState = item.Value switch
                    {
                        0 => DefianceBarStateUpdateEvent.DefianceBarState.Active,
                        1 => DefianceBarStateUpdateEvent.DefianceBarState.Recovering,
                        2 => DefianceBarStateUpdateEvent.DefianceBarState.Immune,
                        3 => DefianceBarStateUpdateEvent.DefianceBarState.None,
                        _ => DefianceBarStateUpdateEvent.DefianceBarState.Unknown
                    };
                    return(new DefianceBarStateUpdateEvent(item.Time, GetAgentByAddress(item.SrcAgent),
                                                           breakbarState));

                case StateChange.BreakbarPercent:
                    // This encoding is inconsistent with the health update.
                    float breakbarHealthFraction = BitConversions.ToSingle(item.Value);
                    return(new DefianceBarHealthUpdateEvent(item.Time, GetAgentByAddress(item.SrcAgent),
                                                            breakbarHealthFraction));

                case StateChange.BuffInfo:
                // TODO: Figure out what the contents are
                case StateChange.BuffFormula:
                // TODO: Figure out what the contents are
                case StateChange.SkillInfo:
                // TODO: Figure out what the contents are
                case StateChange.SkillTiming:
                // TODO: Figure out what the contents are
                case StateChange.Error:
                    // TODO: Implement
                    return(new UnknownEvent(item.Time, item));

                case StateChange.Tag:
                    return(new AgentTagEvent(item.Time, GetAgentByAddress(item.SrcAgent), item.Value));

                case StateChange.Unknown:
                    return(new UnknownEvent(item.Time, item));

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
            else if (item.IsActivation != Activation.None)
            {
                switch (item.IsActivation)
                {
                case Activation.CancelCancel:
                    return(new EndSkillCastEvent(item.Time, GetAgentByAddress(item.SrcAgent),
                                                 GetSkillById(item.SkillId), item.Value, EndSkillCastEvent.SkillEndType.Cancel));

                case Activation.CancelFire:
                    return(new EndSkillCastEvent(item.Time, GetAgentByAddress(item.SrcAgent),
                                                 GetSkillById(item.SkillId), item.Value, EndSkillCastEvent.SkillEndType.Fire));

                case Activation.Normal:
                    return(new StartSkillCastEvent(item.Time, GetAgentByAddress(item.SrcAgent),
                                                   GetSkillById(item.SkillId), item.Value, StartSkillCastEvent.SkillCastType.Normal));

                case Activation.Quickness:
                    return(new StartSkillCastEvent(item.Time, GetAgentByAddress(item.SrcAgent),
                                                   GetSkillById(item.SkillId), item.Value,
                                                   StartSkillCastEvent.SkillCastType.WithQuickness));

                case Activation.Reset:
                    return(new ResetSkillCastEvent(item.Time, GetAgentByAddress(item.SrcAgent),
                                                   GetSkillById(item.SkillId), item.Value));

                case Activation.Unknown:
                    return(new UnknownEvent(item.Time, item));
                }
            }
            else if (item.Buff != 0 && item.IsBuffRemove != BuffRemove.None)
            {
                Skill buff = GetSkillById(item.SkillId);
                int   remainingDuration  = item.Value;
                int   remainingIntensity = item.BuffDmg;
                int   stacksRemoved      = (int)item.Result;
                var   cleansingAgent     = GetAgentByAddress(item.DstAgent);
                var   agent = GetAgentByAddress(item.SrcAgent);
                switch (item.IsBuffRemove)
                {
                case BuffRemove.All:
                    return(new AllStacksRemovedBuffEvent(item.Time, agent, buff, cleansingAgent,
                                                         stacksRemoved));

                case BuffRemove.Single:
                    uint stackId = item.Padding;
                    return(new SingleStackRemovedBuffEvent(item.Time, agent, buff, cleansingAgent,
                                                           remainingDuration, remainingIntensity, stackId));

                case BuffRemove.Manual:
                    return(new ManualStackRemovedBuffEvent(item.Time, agent, buff, cleansingAgent,
                                                           remainingDuration, remainingIntensity));

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
            else if (item.Buff > 0 && item.BuffDmg == 0)
            {
                Skill buff                   = GetSkillById(item.SkillId);
                int   durationApplied        = item.Value;
                uint  durationOfRemovedStack = item.OverstackValue;
                var   agent                  = GetAgentByAddress(item.DstAgent);
                var   sourceAgent            = GetAgentByAddress(item.SrcAgent);
                return(new BuffApplyEvent(item.Time, agent, buff, sourceAgent, durationApplied,
                                          durationOfRemovedStack));
            }
            else if (item.Buff > 0 && item.Value == 0)
            {
                Skill buff       = GetSkillById(item.SkillId);
                int   buffDamage = item.BuffDmg;
                bool  isOffCycle = item.IsOffCycle > 0;
                Agent attacker   = GetAgentByAddress(item.SrcAgent);
                Agent defender   = GetAgentByAddress(item.DstAgent);
                bool  isMoving   = item.IsMoving > 0;
                bool  isNinety   = item.IsNinety > 0;
                bool  isFlanking = item.IsFlanking > 0;
                bool  isIgnored  = item.Result != 0;

                if (isIgnored)
                {
                    var reason = item.Result == (Result)1
                                                ? IgnoredBuffDamageEvent.Reason.InvulnerableBuff
                                                : IgnoredBuffDamageEvent.Reason.InvulnerableSkill;

                    return(new IgnoredBuffDamageEvent(item.Time, attacker, defender, buff, buffDamage,
                                                      isMoving, isNinety, isFlanking, reason));
                }
                else
                {
                    if (isOffCycle)
                    {
                        return(new OffCycleBuffDamageEvent(item.Time, attacker, defender, buff, buffDamage,
                                                           isMoving, isNinety, isFlanking));
                    }
                    else
                    {
                        return(new BuffDamageEvent(item.Time, attacker, defender, buff, buffDamage, isMoving,
                                                   isNinety, isFlanking));
                    }
                }
            }
            else if (item.Buff == 0)
            {
                int   damage       = item.Value;
                uint  shieldDamage = item.OverstackValue;
                Agent attacker     = GetAgentByAddress(item.SrcAgent);
                Agent defender     = GetAgentByAddress(item.DstAgent);
                Skill skill        = GetSkillById(item.SkillId);
                bool  isMoving     = item.IsMoving > 0;
                bool  isNinety     = item.IsNinety > 0;
                bool  isFlanking   = item.IsFlanking > 0;

                // TODO: Rewrite
                bool ignored      = false;
                var  hitResult    = PhysicalDamageEvent.Result.Normal;
                var  ignoreReason = IgnoredPhysicalDamageEvent.Reason.Absorbed;
                switch (item.Result)
                {
                case Result.Normal:
                    hitResult = PhysicalDamageEvent.Result.Normal;
                    break;

                case Result.Critical:
                    hitResult = PhysicalDamageEvent.Result.Critical;
                    break;

                case Result.Glance:
                    hitResult = PhysicalDamageEvent.Result.Glance;
                    break;

                case Result.Block:
                    ignored      = true;
                    ignoreReason = IgnoredPhysicalDamageEvent.Reason.Blocked;
                    break;

                case Result.Evade:
                    ignored      = true;
                    ignoreReason = IgnoredPhysicalDamageEvent.Reason.Evaded;
                    break;

                case Result.Interrupt:
                    hitResult = PhysicalDamageEvent.Result.Interrupt;
                    break;

                case Result.Absorb:
                    ignored      = true;
                    ignoreReason = IgnoredPhysicalDamageEvent.Reason.Absorbed;
                    break;

                case Result.Blind:
                    ignored      = true;
                    ignoreReason = IgnoredPhysicalDamageEvent.Reason.Missed;
                    break;

                case Result.KillingBlow:
                    hitResult = PhysicalDamageEvent.Result.KillingBlow;
                    break;

                case Result.Downed:
                    hitResult = PhysicalDamageEvent.Result.DowningBlow;
                    break;

                case Result.Unknown:
                    return(new UnknownEvent(item.Time, item));

                default:
                    return(new UnknownEvent(item.Time, item));
                }

                if (!ignored)
                {
                    return(new PhysicalDamageEvent(item.Time, attacker, defender, skill, damage, isMoving,
                                                   isNinety, isFlanking, shieldDamage, hitResult));
                }
                else
                {
                    return(new IgnoredPhysicalDamageEvent(item.Time, attacker, defender, skill, damage,
                                                          isMoving, isNinety, isFlanking, shieldDamage, ignoreReason));
                }
            }

            return(new UnknownEvent(item.Time, item));
        }
Beispiel #3
0
        public Log ProcessLog(ParsedLog log)
        {
            var context = new LogProcessorState();

            context.EvtcVersion = log.LogVersion.BuildVersion;

            context.Agents          = GetAgents(log).ToList();
            context.AgentsByAddress = new Dictionary <ulong, Agent>();
            context.AgentsById      = new Dictionary <int, List <Agent> >();
            foreach (var agent in context.Agents)
            {
                foreach (var origin in agent.AgentOrigin.OriginalAgentData)
                {
                    context.AgentsByAddress[origin.Address] = agent;

                    int id = origin.Id;
                    if (!context.AgentsById.TryGetValue(id, out var agentsWithId))
                    {
                        agentsWithId           = new List <Agent>();
                        context.AgentsById[id] = agentsWithId;
                    }

                    agentsWithId.Add(agent);
                }
            }

            context.Skills = GetSkills(log).ToList();
            GetDataFromCombatItems(log, context);

            Agent mainTarget = null;

            context.LogType = LogType.PvE;
            if (log.ParsedBossData.ID == 1)
            {
                context.LogType = LogType.WorldVersusWorld;
            }
            else
            {
                // The boss id be either an NPC species id or a Gadget id.
                // Conflicts may happen, in that case the first found agent is chosen,
                // as they are more likely to be the trigger. It is also possible to have
                // multiple agents with the same id if they are not unique, in that case
                // we once again choose the first one.
                foreach (var agent in context.Agents)
                {
                    if (agent is NPC npc && npc.SpeciesId == log.ParsedBossData.ID ||
                        agent is Gadget gadget && gadget.VolatileId == log.ParsedBossData.ID)
                    {
                        mainTarget = agent;
                        break;
                    }
                }
            }

            SetAgentAwareTimes(context);
            AssignAgentMasters(log, context);             // Has to be done after setting aware times

            context.EncounterData = GetEncounterData(mainTarget, context);

            foreach (var step in context.EncounterData.ProcessingSteps)
            {
                step.Process(context);
            }

            return(new Log(mainTarget, context));
        }
Beispiel #4
0
        private void GetDataFromCombatItems(ParsedLog log, LogProcessorState state)
        {
            Debug.Assert(state.Agents != null);
            Debug.Assert(state.Skills != null);
            Debug.Assert(state.AgentsByAddress != null);

            var skillsById = new Dictionary <uint, Skill>();

            foreach (var skill in state.Skills)
            {
                // Rarely, in old logs a skill may be duplicated (typically a skill with id 0),
                // so we only use the first definition
                if (!skillsById.ContainsKey(skill.Id))
                {
                    skillsById.Add(skill.Id, skill);
                }
            }

            state.GameLanguage = GameLanguage.Other;
            var events = new List <Event>();

            foreach (var item in log.ParsedCombatItems)
            {
                if (item.IsStateChange == StateChange.LogStart)
                {
                    if (state.LogStartTime != null)
                    {
                        throw new LogProcessingException("Multiple log start combat items found");
                    }

                    var serverTime = DateTimeOffset.FromUnixTimeSeconds(item.Value);
                    var localTime  = DateTimeOffset.FromUnixTimeSeconds(item.BuffDmg);

                    state.LogStartTime = new LogTime(localTime, serverTime, item.Time);
                    continue;
                }

                if (item.IsStateChange == StateChange.LogEnd)
                {
                    if (item.Value == 0 && item.BuffDmg == 0)
                    {
                        // This is an erroneous extra log end without any data,
                        // we ignore it. Happened in every log with EVTC20200506.
                        continue;
                    }

                    if (state.LogEndTime != null)
                    {
                        throw new LogProcessingException("Multiple log end combat items found");
                    }

                    var serverTime = DateTimeOffset.FromUnixTimeSeconds(item.Value);
                    var localTime  = DateTimeOffset.FromUnixTimeSeconds(item.BuffDmg);

                    state.LogEndTime = new LogTime(localTime, serverTime, item.Time);
                    continue;
                }

                if (item.IsStateChange == StateChange.PointOfView)
                {
                    if (state.AgentsByAddress.TryGetValue(item.SrcAgent, out var agent))
                    {
                        state.PointOfView = agent as Player ??
                                            throw new LogProcessingException("The point of view agent is not a player");
                    }

                    continue;
                }

                if (item.IsStateChange == StateChange.Language)
                {
                    int languageId = (int)item.SrcAgent;
                    state.GameLanguageId = languageId;
                    state.GameLanguage   = GameLanguageIds.GetLanguageById(languageId);
                    continue;
                }

                if (item.IsStateChange == StateChange.GWBuild)
                {
                    state.GameBuild = (int)item.SrcAgent;
                    continue;
                }

                if (item.IsStateChange == StateChange.ShardId)
                {
                    state.GameShardId = (int)item.SrcAgent;
                    continue;
                }

                if (item.IsStateChange == StateChange.MapId)
                {
                    state.MapId = (int)item.SrcAgent;
                    continue;
                }

                if (item.IsStateChange == StateChange.Guild)
                {
                    if (state.AgentsByAddress.TryGetValue(item.SrcAgent, out Agent agent))
                    {
                        var player = (Player)agent;
                        var guid   = new byte[16];

                        // It is unclear how the arcdps values would be stored on a big-endian platform
                        Debug.Assert(BitConverter.IsLittleEndian);

                        var dstBytes        = BitConverter.GetBytes(item.DstAgent);
                        var valueBytes      = BitConverter.GetBytes(item.Value);
                        var buffDamageBytes = BitConverter.GetBytes(item.BuffDmg);

                        guid[0]  = dstBytes[3];
                        guid[1]  = dstBytes[2];
                        guid[2]  = dstBytes[1];
                        guid[3]  = dstBytes[0];
                        guid[4]  = dstBytes[5];
                        guid[5]  = dstBytes[4];
                        guid[6]  = dstBytes[7];
                        guid[7]  = dstBytes[6];
                        guid[8]  = valueBytes[0];
                        guid[9]  = valueBytes[1];
                        guid[10] = valueBytes[2];
                        guid[11] = valueBytes[3];
                        guid[12] = buffDamageBytes[0];
                        guid[13] = buffDamageBytes[1];
                        guid[14] = buffDamageBytes[2];
                        guid[15] = buffDamageBytes[3];

                        player.GuildGuid = guid;
                    }

                    continue;
                }

                if (item.IsStateChange == StateChange.AttackTarget)
                {
                    // Only used for master assignment
                    // Contains if the attack target is targetable as the value.
                    continue;
                }

                var processedEvent = GetEvent(state, skillsById, item);
                if (!(processedEvent is UnknownEvent) || !IgnoreUnknownEvents)
                {
                    events.Add(processedEvent);
                }
            }

            state.Events = events;
        }
Beispiel #5
0
        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;
        }
Beispiel #6
0
 private IEncounterData GetEncounterData(Agent mainTarget, LogProcessorState state)
 {
     return(EncounterIdentifier.GetEncounterData(mainTarget, state.Events, state.Agents, state.Skills, state.GameBuild, state.LogType));
 }