Beispiel #1
0
        internal static List <TrinityCacheObject> GetCacheObjectHotSpots()
        {
            List <TrinityCacheObject> list = new List <TrinityCacheObject>();

            if (Trinity.Player.IsInTown)
            {
                return(list);
            }

            var hotSpotList = HotSpotList.Where(s =>
                                                s.Location.Distance2D(Trinity.Player.Position) <= V.F("Cache.HotSpot.MaxDistance") &&
                                                s.Location.Distance2D(Trinity.Player.Position) >= V.F("Cache.HotSpot.MinDistance") &&
                                                s.WorldId == Trinity.Player.WorldID).ToList();

            foreach (var hotSpot in hotSpotList)
            {
                Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Adding HotSpot to Cache: {0}", hotSpot);
                var o = new TrinityCacheObject()
                {
                    Position     = hotSpot.Location,
                    InternalName = "HotSpot",
                    Type         = TrinityObjectType.HotSpot,
                    Distance     = Trinity.Player.Position.Distance2D(hotSpot.Location),
                    Radius       = HotSpot.MaxPositionDistance,
                };

                list.Add(o);
            }

            return(list);
        }
 public CacheObstacleObject(TrinityCacheObject tco)
 {
     ActorSNO = tco.ActorSNO;
     Radius = tco.Radius;
     Position = tco.Position;
     RActorGUID = tco.RActorGuid;
     ObjectType = tco.Type;
     Name = tco.InternalName;
 }
 public CacheObstacleObject(TrinityCacheObject tco)
 {
     ActorSNO   = tco.ActorSNO;
     Radius     = tco.Radius;
     Position   = tco.Position;
     RActorGUID = tco.RActorGuid;
     ObjectType = tco.Type;
     Name       = tco.InternalName;
 }
        /// <summary>
        /// Initializes variable set for single object refresh
        /// </summary>
        private static void RefreshStepInit(out bool AddTocache)
        {
            CurrentCacheObject = new TrinityCacheObject();
            AddTocache         = true;
            // Start this object as off as unknown type
            CurrentCacheObject.Type = GObjectType.Unknown;

            CurrentCacheObject.Distance = 0f;
            CurrentCacheObject.Radius   = 0f;
            c_ZDiff           = 0f;
            c_ItemDisplayName = "";
            c_ItemLink        = "";
            CurrentCacheObject.InternalName = "";
            c_IgnoreReason                   = "";
            c_IgnoreSubStep                  = "";
            CurrentCacheObject.ACDGuid       = -1;
            CurrentCacheObject.RActorGuid    = -1;
            CurrentCacheObject.DynamicID     = -1;
            CurrentCacheObject.GameBalanceID = -1;
            CurrentCacheObject.ActorSNO      = -1;
            c_ItemLevel             = -1;
            c_GoldStackSize         = -1;
            c_HitPointsPct          = -1;
            c_HitPoints             = -1;
            c_IsOneHandedItem       = false;
            c_IsTwoHandedItem       = false;
            c_unit_IsElite          = false;
            c_unit_IsRare           = false;
            c_unit_IsUnique         = false;
            c_unit_IsMinion         = false;
            c_unit_IsTreasureGoblin = false;
            c_unit_IsAttackable     = false;
            c_unit_HasShieldAffix   = false;
            c_IsEliteRareUnique     = false;
            c_IsObstacle            = false;
            c_HasBeenNavigable      = false;
            c_HasBeenRaycastable    = false;
            c_HasBeenInLoS          = false;
            c_ItemMd5Hash           = string.Empty;
            c_ItemQuality           = ItemQuality.Invalid;
            c_DBItemBaseType        = ItemBaseType.None;
            c_DBItemType            = ItemType.Unknown;
            c_item_tFollowerType    = FollowerType.None;
            c_item_GItemType        = GItemType.Unknown;
            c_unit_MonsterSize      = MonsterSize.Unknown;
            c_diaObject             = null;
            c_CurrentAnimation      = SNOAnim.Invalid;
            c_HasDotDPS             = false;
            c_MonsterAffixes        = MonsterAffixes.None;
            c_IsFacingPlayer        = false;
            c_Rotation        = 0f;
            c_DirectionVector = Vector2.Zero;
        }
Beispiel #5
0
        /// <summary>
        /// Checks if a unit is currently being tracked with a given SNOPower. When the spell is properly configured, this can be used to set a "timer" on a DoT re-cast, for example.
        /// </summary>
        /// <param name="acdGuid"></param>
        /// <param name="power"></param>
        /// <returns></returns>
        public static bool IsUnitTracked(TrinityCacheObject unit, SNOPower power)
        {
            if (unit.Type != GObjectType.Unit)
            {
                return(false);
            }
            bool result = TrackedUnits.Any(t => t.ACDGuid == unit.ACDGuid && t.Power == power);

            //if (result)
            //    Technicals.Logger.LogNormal("Unit {0} is tracked with power {1}", unit.ACDGuid, power);
            //else
            //    Technicals.Logger.LogNormal("Unit {0} is NOT tracked with power {1}", unit.ACDGuid, power);
            return(result);
        }
Beispiel #6
0
        /// <summary>
        /// Generates an SHA1 hash of a particular CacheObject
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string GenerateObjecthash(TrinityCacheObject obj)
        {
            using (MD5 md5 = MD5.Create())
            {
                string objHashBase;
                if (obj.Type == TrinityObjectType.Unit)
                    objHashBase = obj.ActorSNO + obj.InternalName + obj.Position + obj.Type + Trinity.CurrentWorldDynamicId;
                else if (obj.Type == TrinityObjectType.Item)
                    return GenerateItemHash(obj.Position, obj.ActorSNO, obj.InternalName, Trinity.CurrentWorldId, obj.ItemQuality, obj.ItemLevel);
                else
                    objHashBase = String.Format("{0}{1}{2}{3}", obj.ActorSNO, obj.Position, obj.Type, Trinity.CurrentWorldDynamicId);

                string objHash = GetMd5Hash(md5, objHashBase);
                return objHash;
            }
        }
Beispiel #7
0
 private static void RefreshWaitTimers()
 {
     // See if we should wait for [playersetting] milliseconds for possible loot drops before continuing run
     if (ShouldWaitForLootDrop)
     {
         CurrentTarget = new TrinityCacheObject()
         {
             Position     = Player.Position,
             Type         = TrinityObjectType.Avoidance,
             Weight       = 20000,
             Distance     = 2f,
             Radius       = 2f,
             InternalName = "WaitForLootDrops"
         };
         Logger.Log(TrinityLogLevel.Debug, LogCategory.Behavior, "Waiting for loot to drop, delay: {0}ms", Settings.Combat.Misc.DelayAfterKill);
     }
 }
Beispiel #8
0
        /// <summary>
        /// Generates an SHA1 hash of a particular CacheObject
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string GenerateObjecthash(TrinityCacheObject obj)
        {
            using (MD5 md5 = MD5.Create())
            {
                string objHashBase;
                if (obj.Type == TrinityObjectType.Unit)
                {
                    objHashBase = obj.ActorSNO + obj.InternalName + obj.Position + obj.Type + Trinity.CurrentWorldDynamicId;
                }
                else if (obj.Type == TrinityObjectType.Item)
                {
                    return(GenerateItemHash(obj.Position, obj.ActorSNO, obj.InternalName, Trinity.CurrentWorldId, obj.ItemQuality, obj.ItemLevel));
                }
                else
                {
                    objHashBase = String.Format("{0}{1}{2}{3}", obj.ActorSNO, obj.Position, obj.Type, Trinity.CurrentWorldDynamicId);
                }

                string objHash = GetMd5Hash(md5, objHashBase);
                return(objHash);
            }
        }
Beispiel #9
0
        private static bool AvoidanceLock(out RunStatus handleTarget)
        {
            var criticalAvoidances = new HashSet<AvoidanceType>
            {
                AvoidanceType.MoltenCore,
            };

            // Make the bot continue moving towards safespots 
            if (AvoidanceManager.IsLockedMovingToSafeSpot)
            {
                if (AvoidanceManager.CurrentSafeSpot != CurrentTarget && Player.IsTakingDamage)
                {
                    Logger.Log(LogCategory.Avoidance, "Forcing Target back to locked SafeSpot");
                    CurrentTarget = AvoidanceManager.CurrentSafeSpot;
                }

                var isCloseEnoughToSafeSpot = AvoidanceManager.CurrentSafeSpot.Distance <= 2f;
                var isFarEnoughFromAvoidance = _currentAvoidance.Distance >= _currentAvoidance.AvoidanceRadius;

                if (isCloseEnoughToSafeSpot || isFarEnoughFromAvoidance || PlayerMover.IsBlocked || Navigator.StuckHandler.IsStuck)
                {
                    Logger.Log(LogCategory.Avoidance, "Breaking from Safespot Movement Lock DistanceToSafeSpot={0} DistanceToAvoidance={0}",
                        AvoidanceManager.CurrentSafeSpot.Distance, _currentAvoidance.Distance);

                    AvoidanceManager.IsLockedMovingToSafeSpot = false;
                    {
                        handleTarget = GetRunStatus(RunStatus.Success, "BreakFromSafeSpotLock");
                        return true;
                    }
                }
            }

            var isTooCloseToMonster = CurrentTarget.IsBoss && CurrentTarget.Distance <= CombatBase.KiteDistance;
            var isTooCloseToAvoidance = ObjectCache.Any(o => criticalAvoidances.Contains(o.AvoidanceType) && o.Distance < GetAvoidanceRadius(o.ActorSNO, 30f) && Player.CurrentHealthPct < GetAvoidanceHealth(o.ActorSNO));

            // If we're standing in an avoidance. We're not messing around anymore, hijack this train and move now.
            if (_standingInAvoidance || Player.IsRanged && isTooCloseToMonster || isTooCloseToAvoidance)
            {
                if (isTooCloseToMonster && Player.IsRanged)
                {
                    Logger.LogVerbose(LogCategory.Behavior, "Too close to boss, Kiting! DistanceToTarget={0} KiteTriggerRange={1} KiteMode={2}",
                        CurrentTarget.Distance, CombatBase.KiteDistance, CombatBase.KiteMode);
                }

                var safespot = CurrentTarget.IsSafeSpot && CurrentTarget.Distance > 3f ? CurrentTarget : ObjectCache.Where(o => o.IsSafeSpot).OrderByDescending(o => o.Distance).FirstOrDefault();
                if (safespot == null || safespot.Position == Vector3.Zero || safespot.Distance > 200f)
                {
                    var monstersToAvoid = isTooCloseToMonster ? new List<TrinityCacheObject>() {CurrentTarget} : new List<TrinityCacheObject>();
                    var minDistance = Math.Max(CombatBase.KiteDistance, _currentAvoidance.AvoidanceRadius);
                    var newSafeSpotPosition = NavHelper.MainFindSafeZone(Player.Position, false, false, monstersToAvoid, false, minDistance);
                    var distance = newSafeSpotPosition.Distance(Player.Position);
                    if (newSafeSpotPosition != null && newSafeSpotPosition != Vector3.Zero && distance < 200f)
                    {
                        Logger.Log(LogCategory.Avoidance, "Creating new safe spot Distance={0}", distance);
                        safespot = new TrinityCacheObject()
                        {
                            Position = newSafeSpotPosition,
                            Type = TrinityObjectType.Avoidance,
                            Weight = 90000,
                            Distance = distance,
                            Radius = 2f,
                            InternalName = "SafePoint",
                            IsSafeSpot = true
                        };
                        _currentAvoidance = CurrentTarget;
                        _currentAvoidanceName = CurrentTarget.InternalName;
                        //AvoidanceManager.CurrentSafeSpot = safespot;
                        //AvoidanceManager.IsLockedMovingToSafeSpot = true;
                    }
                    else
                    {
                        Logger.Log(LogCategory.Avoidance, "Unable to find a place to move to :(");
                    }
                }

                if (safespot != null && safespot.Distance > 1f)
                {
                    Logger.LogVerbose(LogCategory.Behavior, "Emergency Avoidance DistanceToTarget={0}, DistanceToAvoidance={1} Avoidance={2} ({3})",
                        CurrentTarget.Distance, _currentAvoidance != null ? _currentAvoidance.Distance : -1, _currentAvoidance != null ? _currentAvoidance.InternalName : "Null", _currentAvoidance != null ? _currentAvoidance.ActorSNO : -1);

                    AvoidanceManager.IsLockedMovingToSafeSpot = true;
                    AvoidanceManager.CurrentSafeSpot = safespot;

                    RunStatus specialMovementResult;
                    if (TrySpecialMovement(out specialMovementResult))
                    {
                        handleTarget = specialMovementResult;
                        return true;
                    }

                    Logger.LogVerbose(LogCategory.Avoidance, "Safespot found, Emergency moving! Distance={0}", safespot.Distance);
                    PlayerMover.NavigateTo(safespot.Position, "EmergencySafeSpot");
                    {
                        handleTarget = RunStatus.Running;
                        return true;
                    }
                }
            }

            handleTarget = RunStatus.Failure;
            return false;
        }
Beispiel #10
0
 /// <summary>
 /// Checks to see if a given Unit is standing in AoE, or if the direct paht-line to the unit goes through AoE
 /// </summary>
 /// <param name="u"></param>
 /// <returns></returns>
 internal static bool UnitOrPathInAoE(TrinityCacheObject u)
 {
     return UnitInAoe(u) && PathToObjectIntersectsAoe(u);
 }
Beispiel #11
0
        private static void RefreshSetKiting(ref Vector3 vKitePointAvoid, bool NeedToKite)
        {
            using (new PerformanceLogger("RefreshDiaObjectCache.Kiting"))
            {
                bool TryToKite = false;

                List <TrinityCacheObject> kiteMonsterList = new List <TrinityCacheObject>();

                if (CurrentTarget != null && CurrentTarget.IsUnit)
                {
                    switch (CombatBase.KiteMode)
                    {
                    case KiteMode.Never:
                        break;

                    case KiteMode.Elites:
                        kiteMonsterList = (from m in ObjectCache
                                           where m.IsUnit &&
                                           m.RadiusDistance > 0 &&
                                           m.RadiusDistance <= CombatBase.KiteDistance &&
                                           m.IsBossOrEliteRareUnique
                                           select m).ToList();
                        break;

                    case KiteMode.Bosses:
                        kiteMonsterList = (from m in ObjectCache
                                           where m.IsUnit &&
                                           m.RadiusDistance > 0 &&
                                           m.RadiusDistance <= CombatBase.KiteDistance &&
                                           m.IsBoss
                                           select m).ToList();
                        break;

                    case KiteMode.Always:
                        kiteMonsterList = (from m in ObjectCache
                                           where m.IsUnit &&
                                           m.Weight > 0 &&
                                           m.RadiusDistance > 0 &&
                                           m.RadiusDistance <= CombatBase.KiteDistance &&
                                           (m.IsBossOrEliteRareUnique ||
                                            ((m.HitPointsPct >= .15 || m.MonsterSize != MonsterSize.Swarm) && !m.IsBossOrEliteRareUnique))
                                           select m).ToList();
                        break;
                    }
                }
                if (kiteMonsterList.Any())
                {
                    TryToKite       = true;
                    vKitePointAvoid = Player.Position;
                }

                if (CombatBase.KiteDistance > 0 && kiteMonsterList.Count() > 0 && IsWizardShouldKite())
                {
                    TryToKite       = true;
                    vKitePointAvoid = Player.Position;
                }

                // Avoid Death
                if (Settings.Combat.Misc.AvoidDeath &&
                    Player.CurrentHealthPct <= CombatBase.EmergencyHealthPotionLimit && // health is lower than potion limit
                    !SNOPowerUseTimer(SNOPower.DrinkHealthPotion) &&                    // we can't use a potion anymore
                    TargetUtil.AnyMobsInRange(90f, false))
                {
                    Logger.LogNormal("Attempting to avoid death!");
                    NeedToKite = true;

                    kiteMonsterList = (from m in ObjectCache
                                       where m.IsUnit
                                       select m).ToList();
                }

                // Note that if treasure goblin level is set to kamikaze, even avoidance moves are disabled to reach the goblin!
                bool shouldKamikazeTreasureGoblins = (!AnyTreasureGoblinsPresent || Settings.Combat.Misc.GoblinPriority <= GoblinPriority.Prioritize);

                double msCancelledEmergency = DateTime.UtcNow.Subtract(timeCancelledEmergencyMove).TotalMilliseconds;
                bool   shouldEmergencyMove  = msCancelledEmergency >= cancelledEmergencyMoveForMilliseconds && NeedToKite;

                double msCancelledKite = DateTime.UtcNow.Subtract(timeCancelledKiteMove).TotalMilliseconds;
                bool   shouldKite      = msCancelledKite >= cancelledKiteMoveForMilliseconds && TryToKite;

                if (shouldKamikazeTreasureGoblins && (shouldEmergencyMove || shouldKite))
                {
                    Vector3 vAnySafePoint = NavHelper.FindSafeZone(false, 1, vKitePointAvoid, true, kiteMonsterList, shouldEmergencyMove);

                    if (LastKitePosition == null)
                    {
                        LastKitePosition = new KitePosition()
                        {
                            PositionFoundTime = DateTime.UtcNow,
                            Position          = vAnySafePoint,
                            Distance          = vAnySafePoint.Distance(Player.Position)
                        };
                    }

                    if (vAnySafePoint != Vector3.Zero && vAnySafePoint.Distance(Player.Position) >= 1)
                    {
                        if ((DateTime.UtcNow.Subtract(LastKitePosition.PositionFoundTime).TotalMilliseconds > 3000 && LastKitePosition.Position == vAnySafePoint) ||
                            (CurrentTarget != null && DateTime.UtcNow.Subtract(lastGlobalCooldownUse).TotalMilliseconds > 1500 && TryToKite))
                        {
                            timeCancelledKiteMove            = DateTime.UtcNow;
                            cancelledKiteMoveForMilliseconds = 1500;
                            Logger.Log(TrinityLogLevel.Debug, LogCategory.UserInformation, "Kite movement failed, cancelling for {0:0}ms", cancelledKiteMoveForMilliseconds);
                            return;
                        }
                        else
                        {
                            LastKitePosition = new KitePosition()
                            {
                                PositionFoundTime = DateTime.UtcNow,
                                Position          = vAnySafePoint,
                                Distance          = vAnySafePoint.Distance(Player.Position)
                            };
                        }

                        if (Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement))
                        {
                            Logger.Log(TrinityLogLevel.Verbose, LogCategory.Movement, "Kiting to: {0} Distance: {1:0} Direction: {2:0}, Health%={3:0.00}, KiteDistance: {4:0}, Nearby Monsters: {5:0} NeedToKite: {6} TryToKite: {7}",
                                       vAnySafePoint, vAnySafePoint.Distance(Player.Position), MathUtil.GetHeading(MathUtil.FindDirectionDegree(Me.Position, vAnySafePoint)),
                                       Player.CurrentHealthPct, CombatBase.KiteDistance, kiteMonsterList.Count(),
                                       NeedToKite, TryToKite);
                        }
                        CurrentTarget = new TrinityCacheObject()
                        {
                            Position     = vAnySafePoint,
                            Type         = TrinityObjectType.Avoidance,
                            Weight       = 90000,
                            Distance     = Vector3.Distance(Player.Position, vAnySafePoint),
                            Radius       = 2f,
                            InternalName = "KitePoint"
                        };
                    }
                }
                else if (!shouldEmergencyMove && NeedToKite)
                {
                    Logger.Log(TrinityLogLevel.Debug, LogCategory.UserInformation, "Emergency movement cancelled for {0:0}ms", DateTime.UtcNow.Subtract(timeCancelledEmergencyMove).TotalMilliseconds - cancelledKiteMoveForMilliseconds);
                }
                else if (!shouldKite && TryToKite)
                {
                    Logger.Log(TrinityLogLevel.Debug, LogCategory.UserInformation, "Kite movement cancelled for {0:0}ms", DateTime.UtcNow.Subtract(timeCancelledKiteMove).TotalMilliseconds - cancelledKiteMoveForMilliseconds);
                }
            }
        }
Beispiel #12
0
        private static void RefreshWaitTimers()
        {

            // See if we should wait for [playersetting] milliseconds for possible loot drops before continuing run
            if (ShouldWaitForLootDrop)
            {
                CurrentTarget = new TrinityCacheObject()
                {
                    Position = Player.Position,
                    Type = TrinityObjectType.Avoidance,
                    Weight = 20000,
                    Distance = 2f,
                    Radius = 2f,
                    InternalName = "WaitForLootDrops"
                };
                Logger.Log(TrinityLogLevel.Debug, LogCategory.Behavior, "Waiting for loot to drop, delay: {0}ms", Settings.Combat.Misc.DelayAfterKill);
            }
        }
Beispiel #13
0
 internal static bool CacheObjectIsInHotSpot(TrinityCacheObject cacheObject)
 {
     return(LocationIsInHotSpot(cacheObject.Position, Trinity.Player.WorldID));
 }
Beispiel #14
0
        // Refresh object list from Diablo 3 memory RefreshDiaObjects()
        private static void RefreshCacheInit()
        {
            using (new PerformanceLogger("RefreshDiaObjectCache.CacheInit"))
            {

                // Update when we last refreshed with current time
                LastRefreshedCache = DateTime.UtcNow;

                // Blank current/last/next targets
                LastPrimaryTargetPosition = CurrentTarget != null ? CurrentTarget.Position : Vector3.Zero;
                KiteAvoidDestination = Vector3.Zero;
                // store last target GUID
                LastTargetRactorGUID = CurrentTarget != null ? CurrentTarget.RActorGuid : -1;
                LastTargetACDGuid = CurrentTarget != null ? CurrentTarget.ACDGuid : -1;

                //reset current target
                CurrentTarget = null;
                // Reset all variables for target-weight finding
                CurrentBotKillRange = Settings.Combat.Misc.NonEliteRange;

                if (AnyTreasureGoblinsPresent && Settings.Combat.Misc.GoblinPriority == GoblinPriority.Kamikaze && CurrentBotKillRange < 60f)
                    CurrentBotKillRange = 60f;

                AnyTreasureGoblinsPresent = false;

                // Max kill range if we're questing
                if (DataDictionary.QuestLevelAreaIds.Contains(Player.LevelAreaId))
                    CurrentBotKillRange = 300f;

                CurrentBotLootRange = CharacterSettings.Instance.LootRadius;
                _shouldStayPutDuringAvoidance = false;

                // Not allowed to kill monsters due to profile/routine/combat targeting settings - just set the kill range to a third
                if (!ProfileManager.CurrentProfile.KillMonsters || !CombatTargeting.Instance.AllowedToKillMonsters)
                {
                    CurrentBotKillRange = 0;
                }

                // Not allowed to loots due to profile/routine/loot targeting settings - just set range to a quarter
                if (!ProfileManager.CurrentProfile.PickupLoot || !LootTargeting.Instance.AllowedToLoot)
                {
                    CurrentBotLootRange = 0;
                }

                if (Player.ActorClass == ActorClass.Barbarian && Hotbar.Contains(SNOPower.Barbarian_WrathOfTheBerserker) && GetHasBuff(SNOPower.Barbarian_WrathOfTheBerserker))
                { //!sp - keep looking for kills while WOTB is up
                    _keepKillRadiusExtendedForSeconds = Math.Max(3, _keepKillRadiusExtendedForSeconds);
                    _timeKeepKillRadiusExtendedUntil = DateTime.UtcNow.AddSeconds(_keepKillRadiusExtendedForSeconds);
                }
                // Counter for how many cycles we extend or reduce our attack/kill radius, and our loot radius, after a last kill
                if (_keepKillRadiusExtendedForSeconds > 0)
                {
                    TimeSpan diffResult = DateTime.UtcNow.Subtract(_timeKeepKillRadiusExtendedUntil);
                    _keepKillRadiusExtendedForSeconds = (int)diffResult.Seconds;
                    //DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Moving, "Kill Radius remaining " + diffResult.Seconds + "s");
                    if (_timeKeepKillRadiusExtendedUntil <= DateTime.UtcNow)
                    {
                        _keepKillRadiusExtendedForSeconds = 0;
                    }
                }
                if (_keepLootRadiusExtendedForSeconds > 0)
                    _keepLootRadiusExtendedForSeconds--;

                // Clear forcing close-range priority on mobs after XX period of time
                if (_forceCloseRangeTarget && DateTime.UtcNow.Subtract(_lastForcedKeepCloseRange).TotalMilliseconds > ForceCloseRangeForMilliseconds)
                {
                    _forceCloseRangeTarget = false;
                }

                //AnyElitesPresent = false;
                AnyMobsInRange = false;

                // Clear our very short-term destructible blacklist within 3 seconds of last attacking a destructible
                if (_needClearDestructibles && DateTime.UtcNow.Subtract(_lastDestroyedDestructible).TotalMilliseconds > 2500)
                {
                    _needClearDestructibles = false;
                    _destructible3SecBlacklist = new HashSet<int>();
                }
                // Clear our very short-term ignore-monster blacklist (from not being able to raycast on them or already dead units)
                if (NeedToClearBlacklist3 && DateTime.UtcNow.Subtract(Blacklist3LastClear).TotalMilliseconds > 3000)
                {
                    NeedToClearBlacklist3 = false;
                    Blacklist3Seconds = new HashSet<int>();
                }

                // Reset the counters for player-owned things
                PlayerOwnedMysticAllyCount = 0;
                PlayerOwnedGargantuanCount = 0;
                PlayerOwnedZombieDogCount = 0;
                PlayerOwnedDHPetsCount = 0;
                PlayerOwnedDHSentryCount = 0;
                PlayerOwnedHydraCount = 0;
                PlayerOwnedAncientCount = 0;

                // Flag for if we should search for an avoidance spot or not
                _standingInAvoidance = false;

                _currentAvoidance = new TrinityCacheObject();
                _currentAvoidanceName = string.Empty;

                // Here's the list we'll use to store each object
                ObjectCache = new List<TrinityCacheObject>();

            }
        }
Beispiel #15
0
        /// <summary>
        /// Adds Legendary & Set Minimap Markers to ObjectCache
        /// </summary>
        private static void RefreshCacheMarkers()
        {
            const int setItemMarkerTexture       = 404424;
            const int legendaryItemMarkerTexture = 275968;

            if (!BrainBehavior.IsVendoring && !WantToTownRun && !ForceVendorRunASAP && Settings.Loot.Pickup.PickupLegendaries)
            {
                var legendaryItemMarkers = ZetaDia.Minimap.Markers.CurrentWorldMarkers.Where(m => m.IsValid &&
                                                                                             m.Position.Distance2D(Player.Position) >= 45f && m.Position.Distance2D(Player.Position) < 300f &&
                                                                                             (m.MinimapTexture == setItemMarkerTexture || m.MinimapTexture == legendaryItemMarkerTexture) && !Blacklist60Seconds.Contains(m.NameHash)).ToList();

                foreach (var marker in legendaryItemMarkers)
                {
                    var name = (marker.MinimapTexture == setItemMarkerTexture ? "Set Item" : "Legendary Item") + " Minimap Marker";

                    var cacheObject = new TrinityCacheObject
                    {
                        Position     = new Vector3((float)Math.Floor(marker.Position.X), (float)Math.Floor(marker.Position.Y), (float)Math.Floor(marker.Position.Z)),
                        InternalName = name,
                        ActorSNO     = marker.NameHash,
                        RActorGuid   = marker.MinimapTexture,
                        Distance     = marker.Position.Distance(Player.Position),
                        ActorType    = ActorType.Item,
                        Type         = TrinityObjectType.Item,
                        ItemQuality  = ItemQuality.Legendary,
                        Radius       = 2f,
                        Weight       = 50,
                        IsMarker     = true
                    };
                    cacheObject.ObjectHash = HashGenerator.GenerateItemHash(cacheObject);

                    if (GenericBlacklist.ContainsKey(cacheObject.ObjectHash))
                    {
                        Logger.LogDebug(LogCategory.CacheManagement, "Ignoring Marker because it's blacklisted {0} {1} at {2} distance {3}", name, marker.MinimapTexture, marker.Position, marker.Position.Distance(Player.Position));
                        continue;
                    }

                    Logger.LogDebug(LogCategory.CacheManagement, "Adding {0} {1} at {2} distance {3}", name, marker.MinimapTexture, marker.Position, marker.Position.Distance(Player.Position));
                    ObjectCache.Add(cacheObject);
                }

                if (legendaryItemMarkers.Any() && TrinityItemManager.FindValidBackpackLocation(true) != new Vector2(-1, -1))
                {
                    var legendaryItems = ZetaDia.Actors.GetActorsOfType <DiaItem>().Where(i => i.IsValid && i.IsACDBased && i.Position.Distance2D(ZetaDia.Me.Position) < 5f &&
                                                                                          legendaryItemMarkers.Any(im => i.Position.Distance2D(i.Position) < 2f));

                    foreach (var diaItem in legendaryItems)
                    {
                        Logger.LogDebug(LogCategory.CacheManagement, "Adding Legendary Item from Marker {0} dist={1} ActorSNO={2} ACD={3} RActor={4}",
                                        diaItem.Name, diaItem.Distance, diaItem.ActorSNO, diaItem.ACDGuid, diaItem.RActorGuid);

                        ObjectCache.Add(new TrinityCacheObject()
                        {
                            Position         = diaItem.Position,
                            InternalName     = diaItem.Name,
                            RActorGuid       = diaItem.RActorGuid,
                            ActorSNO         = diaItem.ActorSNO,
                            ACDGuid          = diaItem.ACDGuid,
                            HasBeenNavigable = true,
                            HasBeenInLoS     = true,
                            Distance         = diaItem.Distance,
                            ActorType        = ActorType.Item,
                            Type             = TrinityObjectType.Item,
                            Radius           = 2f,
                            Weight           = 50,
                            ItemQuality      = ItemQuality.Legendary,
                        });
                    }
                }
            }

            bool isRiftGuardianQuestStep = ZetaDia.CurrentQuest.QuestSNO == 337492 && ZetaDia.CurrentQuest.StepId == 16;

            if (isRiftGuardianQuestStep)
            {
                // Add Rift Guardian POI's or Markers to ObjectCache
                const int riftGuardianMarkerTexture = 81058;
                Func <MinimapMarker, bool> riftGuardianMarkerFunc = m => m.IsValid && (m.IsPointOfInterest || m.MinimapTexture == riftGuardianMarkerTexture) &&
                                                                    !Blacklist60Seconds.Contains(m.NameHash);

                foreach (var marker in ZetaDia.Minimap.Markers.CurrentWorldMarkers.Where(riftGuardianMarkerFunc))
                {
                    Logger.LogDebug(LogCategory.CacheManagement, "Adding Rift Guardian POI, distance {0}", marker.Position.Distance2D(Player.Position));
                    ObjectCache.Add(new TrinityCacheObject()
                    {
                        Position     = marker.Position,
                        InternalName = "Rift Guardian",
                        Distance     = marker.Position.Distance(Player.Position),
                        RActorGuid   = marker.NameHash,
                        ActorType    = ActorType.Monster,
                        Type         = TrinityObjectType.Unit,
                        Radius       = 10f,
                        Weight       = 5000,
                    });
                }
            }

            if (isRiftGuardianQuestStep || Player.ParticipatingInTieredLootRun) // X1_LR_DungeonFinder
            {
                foreach (var marker in ZetaDia.Minimap.Markers.CurrentWorldMarkers.Where(m => m.IsPointOfInterest && !Blacklist60Seconds.Contains(m.NameHash)))
                {
                    ObjectCache.Add(new TrinityCacheObject()
                    {
                        Position     = marker.Position,
                        InternalName = "Rift Guardian",
                        Distance     = marker.Position.Distance(Player.Position),
                        RActorGuid   = marker.NameHash,
                        ActorType    = ActorType.Monster,
                        Type         = TrinityObjectType.Unit,
                        Radius       = 10f,
                        Weight       = 5000,
                    });
                }
            }
        }
Beispiel #16
0
        /// <summary>
        /// This method will add and update necessary information about all available actors. Determines ObjectType, sets ranges, updates blacklists, determines avoidance, kiting, target weighting
        /// and the result is we will have a new target for the Target Handler. Returns true if the cache was refreshed.
        /// </summary>
        /// <returns>True if the cache was updated</returns>
        public static bool RefreshDiaObjectCache()
        {
            if (ZetaDia.Service.Hero == null)
            {
                Logger.LogError("Hero is null!");
                return false;
            }

            //if (!ZetaDia.Service.Hero.IsValid)
            //{
            //    Logger.LogError("Hero is invalid!");
            //    return false;
            //}

            if (!ZetaDia.IsInGame)
                return false;

            if (ZetaDia.IsLoadingWorld)
                return false;

            if (!ZetaDia.Me.IsValid)
                return false;

            if (!ZetaDia.Me.CommonData.IsValid)
                return false;


            using (new PerformanceLogger("RefreshDiaObjectCache"))
            {
                LastRefreshedCache = DateTime.UtcNow;

                /*
                 *  Refresh the Cache
                 */
                using (new PerformanceLogger("RefreshDiaObjectCache.UpdateBlock"))
                {
                    CacheData.Clear();
                    GenericCache.MaintainCache();
                    GenericBlacklist.MaintainBlacklist();


                    if (Player.CurrentHealthPct <= 0)
                    {
                        return false;
                    }

                    RefreshCacheInit();

                    // Now pull up all the data and store anything we want to handle in the super special cache list
                    // Also use many cache dictionaries to minimize DB<->D3 memory hits, and speed everything up a lot
                    RefreshCacheMainLoop();

                }

                /*
                 * Add Legendary & Set Minimap Markers to ObjectCache
                 */
                RefreshCacheMarkers();

                // Add Team HotSpots to the cache
                ObjectCache.AddRange(GroupHotSpots.GetCacheObjectHotSpots());

                /* Fire Chains Experimental Avoidance */
                if (Settings.Combat.Misc.UseExperimentalFireChainsAvoidance)
                {
                    const float fireChainSize = 5f;
                    foreach (var unit1 in ObjectCache.Where(u => u.MonsterAffixes.HasFlag(MonsterAffixes.FireChains)))
                    {
                        foreach (var unit2 in ObjectCache.Where(u => u.MonsterAffixes.HasFlag(MonsterAffixes.FireChains)).Where(unit2 => unit1.RActorGuid != unit2.RActorGuid))
                        {
                            for (float i = 0; i <= unit1.Position.Distance2D(unit2.Position); i += (fireChainSize / 4))
                            {
                                Vector3 fireChainSpot = MathEx.CalculatePointFrom(unit1.Position, unit2.Position, i);

                                if (Player.Position.Distance2D(fireChainSpot) <= fireChainSize)
                                {
                                    Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Avoiding Fire Chains!");
                                    _standingInAvoidance = true;
                                }
                                CacheData.TimeBoundAvoidance.Add(new CacheObstacleObject(fireChainSpot, fireChainSize, -2, "FireChains"));
                            }
                        }
                        if (CacheData.TimeBoundAvoidance.Any(aoe => aoe.ActorSNO == -2))
                            Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Generated {0} avoidance points for FireChains, minDistance={1} maxDistance={2}",
                                CacheData.TimeBoundAvoidance.Count(aoe => aoe.ActorSNO == -2),
                                CacheData.TimeBoundAvoidance.Where(aoe => aoe.ActorSNO == -2)
                                    .Min(aoe => aoe.Position.Distance2D(Trinity.Player.Position)),
                                CacheData.TimeBoundAvoidance.Where(aoe => aoe.ActorSNO == -2)
                                    .Max(aoe => aoe.Position.Distance2D(Trinity.Player.Position)));
                    }
                }

                /* Beast Charge Experimental Avoidance */
                if (Settings.Combat.Misc.UseExperimentalSavageBeastAvoidance)
                {
                    const float beastChargePathWidth = 10f;
                    List<int> chargerSnoList = new List<int>();
                    foreach (var unit1 in ObjectCache.Where(u => objectIsCharging(u)))
                    {
                        Vector3 endPoint = MathEx.GetPointAt(unit1.Position, 90f, unit1.Unit.Movement.Rotation);

                        for (float i = 0; i <= unit1.Position.Distance2D(endPoint); i += (beastChargePathWidth / 4))
                        {
                            Vector3 pathSpot = MathEx.CalculatePointFrom(unit1.Position, endPoint, i);

                            Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement,
                                "Generating Charge Avoidance: {0} dist: {1}",
                                pathSpot, pathSpot.Distance2D(unit1.Position));

                            var minWidth = Math.Max(beastChargePathWidth, unit1.Radius) + 5f;

                            if (Player.Position.Distance2D(pathSpot) <= minWidth)
                            {
                                Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Avoiding Charger!");
                                _standingInAvoidance = true;
                            }
                            CacheData.TimeBoundAvoidance.Add(new CacheObstacleObject(pathSpot, minWidth, unit1.ActorSNO,
                                "Charger"));

                            chargerSnoList.Add(unit1.ActorSNO);
                        }
                        if (CacheData.TimeBoundAvoidance.Any(aoe => chargerSnoList.Contains(aoe.ActorSNO)))
                            Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement,
                                "Generated {0} avoidance points for BeastCharge, minDistance={1} maxDistance={2}",
                                CacheData.TimeBoundAvoidance.Count(aoe => chargerSnoList.Contains(aoe.ActorSNO)),
                                CacheData.TimeBoundAvoidance.Where(aoe => chargerSnoList.Contains(aoe.ActorSNO))
                                    .Min(aoe => aoe.Position.Distance2D(Player.Position)),
                                CacheData.TimeBoundAvoidance.Where(aoe => chargerSnoList.Contains(aoe.ActorSNO))
                                    .Max(aoe => aoe.Position.Distance2D(Player.Position)));
                    }
                }


                // Reduce ignore-for-loops counter
                if (_ignoreTargetForLoops > 0)
                    _ignoreTargetForLoops--;
                // If we have an avoidance under our feet, then create a new object which contains a safety point to move to
                // But only if we aren't force-cancelling avoidance for XX time
                bool hasFoundSafePoint = false;

                using (new PerformanceLogger("RefreshDiaObjectCache.AvoidanceCheck"))
                {
                    if (Settings.Combat.Misc.FleeInGhostMode && Player.IsGhosted)
                        _standingInAvoidance = true;

                    // Note that if treasure goblin level is set to kamikaze, even avoidance moves are disabled to reach the goblin!
                    if (_standingInAvoidance && (!AnyTreasureGoblinsPresent || Settings.Combat.Misc.GoblinPriority <= GoblinPriority.Prioritize) &&
                        DateTime.UtcNow.Subtract(timeCancelledEmergencyMove).TotalMilliseconds >= cancelledEmergencyMoveForMilliseconds)
                    {
                        Vector3 safePosition = NavHelper.FindSafeZone(false, 1, Player.Position, true, null, true);

                        // Ignore avoidance stuff if we're incapacitated or didn't find a safe spot we could reach
                        if (safePosition != Vector3.Zero)
                        {
                            if (Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement))
                            {
                                Logger.Log(TrinityLogLevel.Verbose, LogCategory.Movement, "Kiting Avoidance: {0} Distance: {1:0} Direction: {2:0}, Health%={3:0.00}, KiteDistance: {4:0}",
                                    safePosition, safePosition.Distance(Me.Position), MathUtil.GetHeading(MathUtil.FindDirectionDegree(Me.Position, safePosition)),
                                    Player.CurrentHealthPct, CombatBase.KiteDistance);
                            }

                            hasFoundSafePoint = true;
                            CurrentTarget = new TrinityCacheObject()
                                {
                                    Position = safePosition,
                                    Type = TrinityObjectType.Avoidance,
                                    Weight = 20000,
                                    Distance = Vector3.Distance(Player.Position, safePosition),
                                    Radius = 2f,
                                    InternalName = "SafePoint"
                                }; ;
                        }
                    }
                }

                /*
                 *  Set Weights, assign CurrentTarget
                 */

                if (!hasFoundSafePoint)
                {
                    RefreshDiaGetWeights();

                    RefreshSetKiting(ref KiteAvoidDestination, NeedToKite);
                }

                // Not heading straight for a safe-spot?
                // No valid targets but we were told to stay put?
                if (CurrentTarget == null && _shouldStayPutDuringAvoidance && !_standingInAvoidance && Settings.Combat.Misc.AvoidAoEOutOfCombat)
                {
                    CurrentTarget = new TrinityCacheObject()
                                        {
                                            Position = Player.Position,
                                            Type = TrinityObjectType.Avoidance,
                                            Weight = 20000,
                                            Distance = 2f,
                                            Radius = 2f,
                                            InternalName = "StayPutPoint"
                                        };
                    Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Staying Put During Avoidance");
                }

                // Pre-townrun is too far away
                if (!Player.IsInTown && TownRun.PreTownRunPosition != Vector3.Zero && TownRun.PreTownRunWorldId == Player.WorldID && !ForceVendorRunASAP
                    && TownRun.PreTownRunPosition.Distance2D(Player.Position) <= V.F("Cache.PretownRun.MaxDistance"))
                {
                    Logger.Log(TrinityLogLevel.Debug, LogCategory.UserInformation, "Pre-TownRun position is more than {0} yards away, canceling", V.I("Cache.PretownRun.MaxDistance"));
                    TownRun.PreTownRunPosition = Vector3.Zero;
                    TownRun.PreTownRunWorldId = -1;
                }

                // Reached pre-townrun position
                if (!Player.IsInTown && TownRun.PreTownRunPosition != Vector3.Zero && TownRun.PreTownRunWorldId == Player.WorldID && !ForceVendorRunASAP
                    && TownRun.PreTownRunPosition.Distance2D(Player.Position) <= 15f)
                {
                    Logger.Log(TrinityLogLevel.Debug, LogCategory.UserInformation, "Successfully returned to Pre-TownRun Position");
                    TownRun.PreTownRunPosition = Vector3.Zero;
                    TownRun.PreTownRunWorldId = -1;
                }

                // After a townrun, make sure to return to original TownRun Location
                if (!Player.IsInTown && CurrentTarget == null && TownRun.PreTownRunPosition != Vector3.Zero && TownRun.PreTownRunWorldId == Player.WorldID && !ForceVendorRunASAP)
                {
                    if (TownRun.PreTownRunPosition.Distance2D(Player.Position) > 10f && TownRun.PreTownRunPosition.Distance2D(Player.Position) <= V.F("Cache.PretownRun.MaxDistance"))
                    {
                        CurrentTarget = new TrinityCacheObject()
                        {
                            Position = TownRun.PreTownRunPosition,
                            Type = TrinityObjectType.Avoidance,
                            Weight = 20000,
                            Distance = 2f,
                            Radius = 2f,
                            InternalName = "PreTownRunPosition"
                        };
                        Logger.Log(TrinityLogLevel.Debug, LogCategory.UserInformation, "Returning to Pre-TownRun Position");
                    }
                }

                using (new PerformanceLogger("RefreshDiaObjectCache.FinalChecks"))
                {
                    if (Settings.WorldObject.EnableBountyEvents)
                    {
                        bool eventObjectNear = ObjectCache.Any(o => o.Type == TrinityObjectType.CursedChest || o.Type == TrinityObjectType.CursedShrine);

                        if (!Player.InActiveEvent)
                        {
                            EventStartPosition = Vector3.Zero;
                            EventStartTime = DateTime.MinValue;
                        }

                        // Reset Event time while we have targts
                        if (CurrentTarget != null && Player.InActiveEvent && eventObjectNear)
                        {
                            EventStartTime = DateTime.UtcNow;
                        }

                        if (eventObjectNear)
                        {
                            EventStartPosition = ObjectCache.FirstOrDefault(o => o.Type == TrinityObjectType.CursedChest || o.Type == TrinityObjectType.CursedShrine).Position;
                        }

                        var activeEvent = ZetaDia.ActInfo.ActiveQuests.FirstOrDefault(q => DataDictionary.EventQuests.Contains(q.QuestSNO));

                        const int waitTimeoutSeconds = 90;
                        if (DateTime.UtcNow.Subtract(EventStartTime).TotalSeconds > waitTimeoutSeconds && activeEvent != null)
                        {
                            CacheData.BlacklistedEvents.Add(activeEvent.QuestSNO);
                        }

                        if (CurrentTarget == null && Player.InActiveEvent && EventStartPosition != Vector3.Zero &&
                            DateTime.UtcNow.Subtract(EventStartTime).TotalSeconds < waitTimeoutSeconds &&
                            activeEvent != null && !CacheData.BlacklistedEvents.Contains(activeEvent.QuestSNO))
                        {
                            CurrentTarget = new TrinityCacheObject()
                            {
                                Position = EventStartPosition,
                                Type = TrinityObjectType.Avoidance,
                                Weight = 20000,
                                Distance = 2f,
                                Radius = 2f,
                                InternalName = "WaitForEvent"
                            };
                            Logger.Log("Waiting for Event {0} - Time Remaining: {1:0} seconds",
                                ZetaDia.ActInfo.ActiveQuests.FirstOrDefault(q => DataDictionary.EventQuests.Contains(q.QuestSNO)).Quest,
                                waitTimeoutSeconds - DateTime.UtcNow.Subtract(EventStartTime).TotalSeconds);
                        }
                    }

                    // Still no target, let's see if we should backtrack or wait for wrath to come off cooldown...
                    if (CurrentTarget == null)
                    {
                        RefreshWaitTimers();
                    }

                    // Still no target, let's end it all!
                    if (CurrentTarget == null)
                    {
                        Events.OnCacheUpdatedHandler.Invoke();
                        return true;
                    }

                    if (CurrentTarget.IsUnit)
                        lastHadUnitInSights = DateTime.UtcNow;

                    if (CurrentTarget.IsBossOrEliteRareUnique)
                        lastHadEliteUnitInSights = DateTime.UtcNow;

                    if (CurrentTarget.IsBoss || CurrentTarget.IsBountyObjective)
                        lastHadBossUnitInSights = DateTime.UtcNow;

                    if (CurrentTarget.Type == TrinityObjectType.Container)
                        lastHadContainerInSights = DateTime.UtcNow;

                    // Record the last time our target changed
                    if (LastTargetRactorGUID != CurrentTarget.RActorGuid)
                    {
                        RecordTargetHistory();

                        Logger.Log(TrinityLogLevel.Verbose, LogCategory.Weight,
                            "Found New Target {0} dist={1:0} IsElite={2} Radius={3:0.0} Weight={4:0} ActorSNO={5} " +
                            "Anim={6} TargetedCount={7} Type={8} ",
                            CurrentTarget.InternalName,
                            CurrentTarget.Distance,
                            CurrentTarget.IsEliteRareUnique,
                            CurrentTarget.Radius,
                            CurrentTarget.Weight,
                            CurrentTarget.ActorSNO,
                            CurrentTarget.Animation,
                            CurrentTarget.TimesBeenPrimaryTarget,
                            CurrentTarget.Type
                            );

                        _lastPickedTargetTime = DateTime.UtcNow;
                        _targetLastHealth = 0f;
                    }
                    else
                    {
                        // We're sticking to the same target, so update the target's health cache to check for stucks
                        if (CurrentTarget.IsUnit)
                        {
                            // Check if the health has changed, if so update the target-pick time before we blacklist them again
                            if (CurrentTarget.HitPointsPct != _targetLastHealth)
                            {
                                Logger.Log(TrinityLogLevel.Debug, LogCategory.Weight, "Keeping Target {0} - CurrentTarget.HitPoints: {1:0.00} TargetLastHealth: {2:0.00} ",
                                                CurrentTarget.RActorGuid, CurrentTarget.HitPointsPct, _targetLastHealth);
                                _lastPickedTargetTime = DateTime.UtcNow;
                            }
                            // Now store the target's last-known health
                            _targetLastHealth = CurrentTarget.HitPointsPct;
                        }
                    }
                }

                // Store less important objects.
                if (ObjectCache.Count > 1)
                {
                    var setting = Settings.Advanced.CacheWeightThresholdPct;
                    var threshold = setting > 0 && CurrentTarget != null ? CurrentTarget.Weight * ((double)setting / 100) : 0;

                    var lowPriorityObjects = ObjectCache.DistinctBy(c => c.RActorGuid).Where(c =>
                        c.Type != TrinityObjectType.Avoidance && c.Type != TrinityObjectType.Unit ||
                        c.Weight < threshold && c.Distance > 12f && !c.IsElite
                        ).ToDictionary(x => x.RActorGuid, x => x);

                    Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Cached {0}/{1} ({2:0}%) WeightThreshold={3}",
                        lowPriorityObjects.Count,
                        ObjectCache.Count,
                        lowPriorityObjects.Count > 0 ? ((double)lowPriorityObjects.Count / ObjectCache.Count) * 100 : 0,
                        threshold);

                    CacheData.LowPriorityObjectCache = lowPriorityObjects;
                }

                // We have a target and the cached was refreshed
                Events.OnCacheUpdatedHandler.Invoke();
                return true;
            }
        }
Beispiel #17
0
        /*
         * Reference implementation: http://msdn.microsoft.com/en-us/library/s02tk69a.aspx
         */

        public static string GenerateItemHash(TrinityCacheObject item)
        {
            return GenerateItemHash(item.Position, item.ActorSNO, item.InternalName, Trinity.Player.WorldID, item.ItemQuality, item.ItemLevel);
        }
Beispiel #18
0
 /// <summary>
 /// Checks to see if a given Unit is standing in AoE
 /// </summary>
 /// <param name="u"></param>
 /// <returns></returns>
 internal static bool UnitInAoe(TrinityCacheObject u)
 {
     return CacheData.TimeBoundAvoidance.Any(aoe => aoe.Position.Distance2D(u.Position) <= aoe.Radius);
 }
Beispiel #19
0
        /*
         * Reference implementation: http://msdn.microsoft.com/en-us/library/s02tk69a.aspx
         */

        public static string GenerateItemHash(TrinityCacheObject item)
        {
            return(GenerateItemHash(item.Position, item.ActorSNO, item.InternalName, Trinity.Player.WorldID, item.ItemQuality, item.ItemLevel));
        }
Beispiel #20
0
        /// <summary>
        /// This method will add and update necessary information about all available actors. Determines ObjectType, sets ranges, updates blacklists, determines avoidance, kiting, target weighting
        /// and the result is we will have a new target for the Target Handler. Returns true if the cache was refreshed.
        /// </summary>
        /// <returns>True if the cache was updated</returns>
        public static bool RefreshDiaObjectCache()
        {
            if (ZetaDia.Service.Hero == null)
            {
                Logger.LogError("Hero is null!");
                return(false);
            }

            //if (!ZetaDia.Service.Hero.IsValid)
            //{
            //    Logger.LogError("Hero is invalid!");
            //    return false;
            //}

            if (!ZetaDia.IsInGame)
            {
                return(false);
            }

            if (ZetaDia.IsLoadingWorld)
            {
                return(false);
            }

            if (!ZetaDia.Me.IsValid)
            {
                return(false);
            }

            if (!ZetaDia.Me.CommonData.IsValid)
            {
                return(false);
            }


            using (new PerformanceLogger("RefreshDiaObjectCache"))
            {
                LastRefreshedCache = DateTime.UtcNow;

                /*
                 *  Refresh the Cache
                 */
                using (new PerformanceLogger("RefreshDiaObjectCache.UpdateBlock"))
                {
                    CacheData.Clear();
                    GenericCache.MaintainCache();
                    GenericBlacklist.MaintainBlacklist();


                    if (Player.CurrentHealthPct <= 0)
                    {
                        return(false);
                    }

                    RefreshCacheInit();

                    // Now pull up all the data and store anything we want to handle in the super special cache list
                    // Also use many cache dictionaries to minimize DB<->D3 memory hits, and speed everything up a lot
                    RefreshCacheMainLoop();
                }

                /*
                 * Add Legendary & Set Minimap Markers to ObjectCache
                 */
                RefreshCacheMarkers();

                // Add Team HotSpots to the cache
                ObjectCache.AddRange(GroupHotSpots.GetCacheObjectHotSpots());

                /* Fire Chains Experimental Avoidance */
                if (Settings.Combat.Misc.UseExperimentalFireChainsAvoidance)
                {
                    const float fireChainSize = 5f;
                    foreach (var unit1 in ObjectCache.Where(u => u.MonsterAffixes.HasFlag(MonsterAffixes.FireChains)))
                    {
                        foreach (var unit2 in ObjectCache.Where(u => u.MonsterAffixes.HasFlag(MonsterAffixes.FireChains)).Where(unit2 => unit1.RActorGuid != unit2.RActorGuid))
                        {
                            for (float i = 0; i <= unit1.Position.Distance2D(unit2.Position); i += (fireChainSize / 4))
                            {
                                Vector3 fireChainSpot = MathEx.CalculatePointFrom(unit1.Position, unit2.Position, i);

                                if (Player.Position.Distance2D(fireChainSpot) <= fireChainSize)
                                {
                                    Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Avoiding Fire Chains!");
                                    _standingInAvoidance = true;
                                }
                                CacheData.TimeBoundAvoidance.Add(new CacheObstacleObject(fireChainSpot, fireChainSize, -2, "FireChains"));
                            }
                        }
                        if (CacheData.TimeBoundAvoidance.Any(aoe => aoe.ActorSNO == -2))
                        {
                            Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Generated {0} avoidance points for FireChains, minDistance={1} maxDistance={2}",
                                       CacheData.TimeBoundAvoidance.Count(aoe => aoe.ActorSNO == -2),
                                       CacheData.TimeBoundAvoidance.Where(aoe => aoe.ActorSNO == -2)
                                       .Min(aoe => aoe.Position.Distance2D(Player.Position)),
                                       CacheData.TimeBoundAvoidance.Where(aoe => aoe.ActorSNO == -2)
                                       .Max(aoe => aoe.Position.Distance2D(Player.Position)));
                        }
                    }
                }

                /* Beast Charge Experimental Avoidance */
                if (Settings.Combat.Misc.UseExperimentalSavageBeastAvoidance)
                {
                    const float beastChargePathWidth = 10f;
                    List <int>  chargerSnoList       = new List <int>();
                    foreach (var unit1 in ObjectCache.Where(u => objectIsCharging(u)))
                    {
                        Vector3 endPoint = MathEx.GetPointAt(unit1.Position, 90f, unit1.Unit.Movement.Rotation);

                        for (float i = 0; i <= unit1.Position.Distance2D(endPoint); i += (beastChargePathWidth / 4))
                        {
                            Vector3 pathSpot = MathEx.CalculatePointFrom(unit1.Position, endPoint, i);

                            Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement,
                                       "Generating Charge Avoidance: {0} dist: {1}",
                                       pathSpot, pathSpot.Distance2D(unit1.Position));

                            var minWidth = Math.Max(beastChargePathWidth, unit1.Radius) + 5f;

                            if (Player.Position.Distance2D(pathSpot) <= minWidth)
                            {
                                Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Avoiding Charger!");
                                _standingInAvoidance = true;
                            }
                            CacheData.TimeBoundAvoidance.Add(new CacheObstacleObject(pathSpot, minWidth, unit1.ActorSNO,
                                                                                     "Charger"));

                            chargerSnoList.Add(unit1.ActorSNO);
                        }
                        if (CacheData.TimeBoundAvoidance.Any(aoe => chargerSnoList.Contains(aoe.ActorSNO)))
                        {
                            Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement,
                                       "Generated {0} avoidance points for BeastCharge, minDistance={1} maxDistance={2}",
                                       CacheData.TimeBoundAvoidance.Count(aoe => chargerSnoList.Contains(aoe.ActorSNO)),
                                       CacheData.TimeBoundAvoidance.Where(aoe => chargerSnoList.Contains(aoe.ActorSNO))
                                       .Min(aoe => aoe.Position.Distance2D(Player.Position)),
                                       CacheData.TimeBoundAvoidance.Where(aoe => chargerSnoList.Contains(aoe.ActorSNO))
                                       .Max(aoe => aoe.Position.Distance2D(Player.Position)));
                        }
                    }
                }


                // Reduce ignore-for-loops counter
                if (_ignoreTargetForLoops > 0)
                {
                    _ignoreTargetForLoops--;
                }
                // If we have an avoidance under our feet, then create a new object which contains a safety point to move to
                // But only if we aren't force-cancelling avoidance for XX time
                bool hasFoundSafePoint = false;

                using (new PerformanceLogger("RefreshDiaObjectCache.AvoidanceCheck"))
                {
                    if (Settings.Combat.Misc.FleeInGhostMode && Player.IsGhosted)
                    {
                        _standingInAvoidance = true;
                    }

                    // Note that if treasure goblin level is set to kamikaze, even avoidance moves are disabled to reach the goblin!
                    if (_standingInAvoidance && !CombatBase.IsDoingGoblinKamakazi && (!AnyTreasureGoblinsPresent || Settings.Combat.Misc.GoblinPriority <= GoblinPriority.Prioritize) &&
                        DateTime.UtcNow.Subtract(timeCancelledEmergencyMove).TotalMilliseconds >= cancelledEmergencyMoveForMilliseconds)
                    {
                        Vector3 safePosition = NavHelper.FindSafeZone(false, 1, Player.Position, true, null, true);

                        // Ignore avoidance stuff if we're incapacitated or didn't find a safe spot we could reach
                        if (safePosition != Vector3.Zero)
                        {
                            if (Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement))
                            {
                                Logger.Log(TrinityLogLevel.Verbose, LogCategory.Movement, "Kiting Avoidance: {5} {0} Distance: {1:0} Direction: {2:0}, Health%={3:0.00}, KiteDistance: {4:0}",
                                           safePosition, safePosition.Distance(Me.Position), MathUtil.GetHeading(MathUtil.FindDirectionDegree(Me.Position, safePosition)),
                                           Player.CurrentHealthPct, CombatBase.KiteDistance, _currentAvoidanceName);
                            }

                            hasFoundSafePoint = true;
                            var distance = Vector3.Distance(Player.Position, safePosition);
                            Logger.Log(LogCategory.Avoidance, "Found Safe Spot {0}f away", distance);
                            CurrentTarget = new TrinityCacheObject()
                            {
                                Position     = safePosition,
                                Type         = TrinityObjectType.Avoidance,
                                Weight       = 40000,
                                Distance     = distance,
                                Radius       = 2f,
                                InternalName = "SafePoint",
                                IsSafeSpot   = true
                            };
                        }
                    }
                }

                /*
                 *  Set Weights, assign CurrentTarget
                 */

                if (!hasFoundSafePoint)
                {
                    RefreshDiaGetWeights();

                    if (!CombatBase.IsDoingGoblinKamakazi)
                    {
                        RefreshSetKiting(ref KiteAvoidDestination, NeedToKite);
                    }
                }

                // Not heading straight for a safe-spot?
                // No valid targets but we were told to stay put?
                if (CurrentTarget == null && !CombatBase.IsDoingGoblinKamakazi && _shouldStayPutDuringAvoidance && !_standingInAvoidance)
                {
                    CurrentTarget = new TrinityCacheObject()
                    {
                        Position     = Player.Position,
                        Type         = TrinityObjectType.Avoidance,
                        Weight       = 45000,
                        Distance     = 2f,
                        Radius       = 2f,
                        InternalName = "StayPutPoint",
                        IsSafeSpot   = true,
                    };
                    Logger.Log(TrinityLogLevel.Debug, LogCategory.Avoidance, "Staying Put During Avoidance");
                }

                // Pre-townrun is too far away
                if (!Player.IsInTown && TownRun.PreTownRunPosition != Vector3.Zero && TownRun.PreTownRunWorldId == Player.WorldID && !ForceVendorRunASAP &&
                    TownRun.PreTownRunPosition.Distance2D(Player.Position) <= V.F("Cache.PretownRun.MaxDistance"))
                {
                    Logger.Log(TrinityLogLevel.Debug, LogCategory.UserInformation, "Pre-TownRun position is more than {0} yards away, canceling", V.I("Cache.PretownRun.MaxDistance"));
                    TownRun.PreTownRunPosition = Vector3.Zero;
                    TownRun.PreTownRunWorldId  = -1;
                }

                // Reached pre-townrun position
                if (!Player.IsInTown && TownRun.PreTownRunPosition != Vector3.Zero && TownRun.PreTownRunWorldId == Player.WorldID && !ForceVendorRunASAP &&
                    TownRun.PreTownRunPosition.Distance2D(Player.Position) <= 15f)
                {
                    Logger.Log(TrinityLogLevel.Debug, LogCategory.UserInformation, "Successfully returned to Pre-TownRun Position");
                    TownRun.PreTownRunPosition = Vector3.Zero;
                    TownRun.PreTownRunWorldId  = -1;
                }

                // After a townrun, make sure to return to original TownRun Location
                if (!Player.IsInTown && CurrentTarget == null && TownRun.PreTownRunPosition != Vector3.Zero && TownRun.PreTownRunWorldId == Player.WorldID && !ForceVendorRunASAP)
                {
                    if (TownRun.PreTownRunPosition.Distance2D(Player.Position) > 10f && TownRun.PreTownRunPosition.Distance2D(Player.Position) <= V.F("Cache.PretownRun.MaxDistance"))
                    {
                        CurrentTarget = new TrinityCacheObject()
                        {
                            Position     = TownRun.PreTownRunPosition,
                            Type         = TrinityObjectType.Avoidance,
                            Weight       = 20000,
                            Distance     = 2f,
                            Radius       = 2f,
                            InternalName = "PreTownRunPosition"
                        };
                        Logger.Log(TrinityLogLevel.Debug, LogCategory.UserInformation, "Returning to Pre-TownRun Position");
                    }
                }

                using (new PerformanceLogger("RefreshDiaObjectCache.FinalChecks"))
                {
                    if (Settings.WorldObject.EnableBountyEvents && !CombatBase.IsDoingGoblinKamakazi)
                    {
                        bool eventObjectNear = ObjectCache.Any(o => o.Type == TrinityObjectType.CursedChest || o.Type == TrinityObjectType.CursedShrine);

                        if (!Player.InActiveEvent)
                        {
                            EventStartPosition = Vector3.Zero;
                            EventStartTime     = DateTime.MinValue;
                        }

                        // Reset Event time while we have targts
                        if (CurrentTarget != null && Player.InActiveEvent && eventObjectNear)
                        {
                            EventStartTime = DateTime.UtcNow;
                        }

                        if (eventObjectNear)
                        {
                            EventStartPosition = ObjectCache.FirstOrDefault(o => o.Type == TrinityObjectType.CursedChest || o.Type == TrinityObjectType.CursedShrine).Position;
                        }

                        var activeEvent = ZetaDia.ActInfo.ActiveQuests.FirstOrDefault(q => DataDictionary.EventQuests.Contains(q.QuestSNO));

                        const int waitTimeoutSeconds = 90;
                        if (DateTime.UtcNow.Subtract(EventStartTime).TotalSeconds > waitTimeoutSeconds && activeEvent != null)
                        {
                            CacheData.BlacklistedEvents.Add(activeEvent.QuestSNO);
                        }

                        if (CurrentTarget == null && Player.InActiveEvent && EventStartPosition != Vector3.Zero &&
                            DateTime.UtcNow.Subtract(EventStartTime).TotalSeconds < waitTimeoutSeconds &&
                            activeEvent != null && !CacheData.BlacklistedEvents.Contains(activeEvent.QuestSNO))
                        {
                            CurrentTarget = new TrinityCacheObject()
                            {
                                Position     = EventStartPosition,
                                Type         = TrinityObjectType.Avoidance,
                                Weight       = 20000,
                                Distance     = 2f,
                                Radius       = 2f,
                                InternalName = "WaitForEvent"
                            };
                            Logger.Log("Waiting for Event {0} - Time Remaining: {1:0} seconds",
                                       ZetaDia.ActInfo.ActiveQuests.FirstOrDefault(q => DataDictionary.EventQuests.Contains(q.QuestSNO)).Quest,
                                       waitTimeoutSeconds - DateTime.UtcNow.Subtract(EventStartTime).TotalSeconds);
                        }
                    }

                    if (CombatBase.IsDoingGoblinKamakazi && CurrentTarget != null && CurrentTarget.Type != TrinityObjectType.Door && CurrentTarget.Type != TrinityObjectType.Barricade && !CurrentTarget.InternalName.ToLower().Contains("corrupt") && CurrentTarget.Weight != MaxWeight)
                    {
                        Logger.Log("Forcing Target to Goblin '{0} ({1})' Distance={2}", CombatBase.KamakaziGoblin.InternalName, CombatBase.KamakaziGoblin.ActorSNO, CombatBase.KamakaziGoblin.Distance);
                        CurrentTarget = CombatBase.KamakaziGoblin;
                    }

                    if (CombatBase.IsDoingGoblinKamakazi && CurrentTarget == null)
                    {
                        Logger.Log("No Target, Switching to Goblin '{0} ({1})' Distance={2}", CombatBase.KamakaziGoblin.InternalName, CombatBase.KamakaziGoblin.ActorSNO, CombatBase.KamakaziGoblin.Distance);
                        CurrentTarget = CombatBase.KamakaziGoblin;
                    }

                    // Still no target, let's see if we should backtrack or wait for wrath to come off cooldown...
                    if (CurrentTarget == null)
                    {
                        RefreshWaitTimers();
                    }

                    // Still no target, let's end it all!
                    if (CurrentTarget == null)
                    {
                        Events.OnCacheUpdatedHandler.Invoke();
                        return(true);
                    }

                    if (CurrentTarget.IsUnit)
                    {
                        lastHadUnitInSights = DateTime.UtcNow;
                    }

                    if (CurrentTarget.IsBossOrEliteRareUnique)
                    {
                        lastHadEliteUnitInSights = DateTime.UtcNow;
                    }

                    if (CurrentTarget.IsBoss || CurrentTarget.IsBountyObjective)
                    {
                        lastHadBossUnitInSights = DateTime.UtcNow;
                    }

                    if (CurrentTarget.Type == TrinityObjectType.Container)
                    {
                        lastHadContainerInSights = DateTime.UtcNow;
                    }

                    // Record the last time our target changed
                    if (LastTargetRactorGUID != CurrentTarget.RActorGuid)
                    {
                        RecordTargetHistory();

                        Logger.Log(TrinityLogLevel.Verbose, LogCategory.Weight,
                                   "Found New Target {0} dist={1:0} IsElite={2} Radius={3:0.0} Weight={4:0} ActorSNO={5} " +
                                   "Anim={6} TargetedCount={7} Type={8} ",
                                   CurrentTarget.InternalName,
                                   CurrentTarget.Distance,
                                   CurrentTarget.IsEliteRareUnique,
                                   CurrentTarget.Radius,
                                   CurrentTarget.Weight,
                                   CurrentTarget.ActorSNO,
                                   CurrentTarget.Animation,
                                   CurrentTarget.TimesBeenPrimaryTarget,
                                   CurrentTarget.Type
                                   );

                        _lastPickedTargetTime = DateTime.UtcNow;
                        _targetLastHealth     = 0f;
                    }
                    else
                    {
                        // We're sticking to the same target, so update the target's health cache to check for stucks
                        if (CurrentTarget.IsUnit)
                        {
                            // Check if the health has changed, if so update the target-pick time before we blacklist them again
                            if (CurrentTarget.HitPointsPct != _targetLastHealth)
                            {
                                Logger.Log(TrinityLogLevel.Debug, LogCategory.Weight, "Keeping Target {0} - CurrentTarget.HitPoints: {1:0.00} TargetLastHealth: {2:0.00} ",
                                           CurrentTarget.RActorGuid, CurrentTarget.HitPointsPct, _targetLastHealth);
                                _lastPickedTargetTime = DateTime.UtcNow;
                            }
                            // Now store the target's last-known health
                            _targetLastHealth = CurrentTarget.HitPointsPct;
                        }
                    }
                }

                // Store less important objects.
                if (ObjectCache.Count > 1)
                {
                    var setting   = Settings.Advanced.CacheWeightThresholdPct;
                    var threshold = setting > 0 && CurrentTarget != null ? CurrentTarget.Weight * ((double)setting / 100) : 0;

                    var lowPriorityObjects = ObjectCache.DistinctBy(c => c.RActorGuid).Where(c =>
                                                                                             c.Type != TrinityObjectType.Avoidance && c.Type != TrinityObjectType.Unit ||
                                                                                             c.Weight <threshold && c.Distance> 12f && !c.IsElite
                                                                                             ).ToDictionary(x => x.RActorGuid, x => x);

                    Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Cached {0}/{1} ({2:0}%) WeightThreshold={3}",
                               lowPriorityObjects.Count,
                               ObjectCache.Count,
                               lowPriorityObjects.Count > 0 ? ((double)lowPriorityObjects.Count / ObjectCache.Count) * 100 : 0,
                               threshold);

                    CacheData.LowPriorityObjectCache = lowPriorityObjects;
                }

                // We have a target and the cached was refreshed
                Events.OnCacheUpdatedHandler.Invoke();
                return(true);
            }
        }
Beispiel #21
0
        // Refresh object list from Diablo 3 memory RefreshDiaObjects()
        private static void RefreshCacheInit()
        {
            using (new PerformanceLogger("RefreshDiaObjectCache.CacheInit"))
            {
                // Update when we last refreshed with current time
                LastRefreshedCache = DateTime.UtcNow;

                // Blank current/last/next targets
                LastPrimaryTargetPosition = CurrentTarget != null ? CurrentTarget.Position : Vector3.Zero;
                KiteAvoidDestination      = Vector3.Zero;
                // store last target GUID
                LastTargetRactorGUID = CurrentTarget != null ? CurrentTarget.RActorGuid : -1;
                LastTargetACDGuid    = CurrentTarget != null ? CurrentTarget.ACDGuid : -1;

                //reset current target
                CurrentTarget = null;
                // Reset all variables for target-weight finding
                CurrentBotKillRange = Settings.Combat.Misc.NonEliteRange;

                if (AnyTreasureGoblinsPresent && Settings.Combat.Misc.GoblinPriority == GoblinPriority.Kamikaze && CurrentBotKillRange < 60f)
                {
                    CurrentBotKillRange = 60f;
                }

                AnyTreasureGoblinsPresent = false;

                // Max kill range if we're questing
                if (DataDictionary.QuestLevelAreaIds.Contains(Player.LevelAreaId))
                {
                    CurrentBotKillRange = 300f;
                }

                CurrentBotLootRange           = CharacterSettings.Instance.LootRadius;
                _shouldStayPutDuringAvoidance = false;

                // Not allowed to kill monsters due to profile/routine/combat targeting settings - just set the kill range to a third
                if (!ProfileManager.CurrentProfile.KillMonsters || !CombatTargeting.Instance.AllowedToKillMonsters)
                {
                    CurrentBotKillRange = 0;
                }

                // Not allowed to loots due to profile/routine/loot targeting settings - just set range to a quarter
                if (!ProfileManager.CurrentProfile.PickupLoot || !LootTargeting.Instance.AllowedToLoot)
                {
                    CurrentBotLootRange = 0;
                }

                if (Player.ActorClass == ActorClass.Barbarian && Hotbar.Contains(SNOPower.Barbarian_WrathOfTheBerserker) && GetHasBuff(SNOPower.Barbarian_WrathOfTheBerserker))
                { //!sp - keep looking for kills while WOTB is up
                    _keepKillRadiusExtendedForSeconds = Math.Max(3, _keepKillRadiusExtendedForSeconds);
                    _timeKeepKillRadiusExtendedUntil  = DateTime.UtcNow.AddSeconds(_keepKillRadiusExtendedForSeconds);
                }
                // Counter for how many cycles we extend or reduce our attack/kill radius, and our loot radius, after a last kill
                if (_keepKillRadiusExtendedForSeconds > 0)
                {
                    TimeSpan diffResult = DateTime.UtcNow.Subtract(_timeKeepKillRadiusExtendedUntil);
                    _keepKillRadiusExtendedForSeconds = (int)diffResult.Seconds;
                    //DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Moving, "Kill Radius remaining " + diffResult.Seconds + "s");
                    if (_timeKeepKillRadiusExtendedUntil <= DateTime.UtcNow)
                    {
                        _keepKillRadiusExtendedForSeconds = 0;
                    }
                }
                if (_keepLootRadiusExtendedForSeconds > 0)
                {
                    _keepLootRadiusExtendedForSeconds--;
                }

                // Clear forcing close-range priority on mobs after XX period of time
                if (_forceCloseRangeTarget && DateTime.UtcNow.Subtract(_lastForcedKeepCloseRange).TotalMilliseconds > ForceCloseRangeForMilliseconds)
                {
                    _forceCloseRangeTarget = false;
                }

                //AnyElitesPresent = false;
                AnyMobsInRange = false;

                // Clear our very short-term destructible blacklist within 3 seconds of last attacking a destructible
                if (_needClearDestructibles && DateTime.UtcNow.Subtract(_lastDestroyedDestructible).TotalMilliseconds > 2500)
                {
                    _needClearDestructibles    = false;
                    _destructible3SecBlacklist = new HashSet <int>();
                }
                // Clear our very short-term ignore-monster blacklist (from not being able to raycast on them or already dead units)
                if (NeedToClearBlacklist3 && DateTime.UtcNow.Subtract(Blacklist3LastClear).TotalMilliseconds > 3000)
                {
                    NeedToClearBlacklist3 = false;
                    Blacklist3Seconds     = new HashSet <int>();
                }

                // Reset the counters for player-owned things
                PlayerOwnedMysticAllyCount = 0;
                PlayerOwnedGargantuanCount = 0;
                PlayerOwnedZombieDogCount  = 0;
                PlayerOwnedDHPetsCount     = 0;
                PlayerOwnedDHSentryCount   = 0;
                PlayerOwnedHydraCount      = 0;
                PlayerOwnedAncientCount    = 0;

                // Flag for if we should search for an avoidance spot or not
                _standingInAvoidance = false;

                _currentAvoidance     = new TrinityCacheObject();
                _currentAvoidanceName = string.Empty;

                // Here's the list we'll use to store each object
                ObjectCache = new List <TrinityCacheObject>();
            }
        }
Beispiel #22
0
 /// <summary>
 /// Checks to see if the path-line to a unit goes through AoE
 /// </summary>
 /// <param name="obj"></param>
 /// <returns></returns>
 internal static bool PathToObjectIntersectsAoe(TrinityCacheObject obj)
 {
     return CacheData.TimeBoundAvoidance.Any(aoe =>
         MathUtil.IntersectsPath(aoe.Position, aoe.Radius, obj.Position, Player.Position));
 }
Beispiel #23
0
 /// <summary>
 /// Checks to see if a given Unit is standing in AoE, or if the direct paht-line to the unit goes through AoE
 /// </summary>
 /// <param name="u"></param>
 /// <returns></returns>
 internal static bool UnitOrPathInAoE(TrinityCacheObject u)
 {
     return(UnitInAoe(u) && PathToObjectIntersectsAoe(u));
 }
Beispiel #24
0
 /// <summary>
 /// Checks to see if a given Unit is standing in AoE
 /// </summary>
 /// <param name="u"></param>
 /// <returns></returns>
 internal static bool UnitInAoe(TrinityCacheObject u)
 {
     return(CacheData.TimeBoundAvoidance.Any(aoe => aoe.Position.Distance2D(u.Position) <= aoe.Radius));
 }
Beispiel #25
0
 /// <summary>
 /// Checks to see if the path-line to a unit goes through AoE
 /// </summary>
 /// <param name="obj"></param>
 /// <returns></returns>
 internal static bool PathToObjectIntersectsAoe(TrinityCacheObject obj)
 {
     return(CacheData.TimeBoundAvoidance.Any(aoe =>
                                             MathUtil.IntersectsPath(aoe.Position, aoe.Radius, obj.Position, Player.Position)));
 }
Beispiel #26
0
        /// <summary>
        /// Adds Legendary & Set Minimap Markers to ObjectCache
        /// </summary>
        private static void RefreshCacheMarkers()
        {
            const int setItemMarkerTexture = 404424;
            const int legendaryItemMarkerTexture = 275968;

            if (!BrainBehavior.IsVendoring && !WantToTownRun && !ForceVendorRunASAP && Settings.Loot.Pickup.PickupLegendaries)
            {
                var legendaryItemMarkers = ZetaDia.Minimap.Markers.CurrentWorldMarkers.Where(m => m.IsValid &&
                                    m.Position.Distance2D(Player.Position) >= 45f && m.Position.Distance2D(Player.Position) < 300f &&
                                    (m.MinimapTexture == setItemMarkerTexture || m.MinimapTexture == legendaryItemMarkerTexture) && !Blacklist60Seconds.Contains(m.NameHash)).ToList();

                foreach (var marker in legendaryItemMarkers)
                {
                    var name = (marker.MinimapTexture == setItemMarkerTexture ? "Set Item" : "Legendary Item") + " Minimap Marker";

                    var cacheObject = new TrinityCacheObject
                    {
                        Position = new Vector3((float)Math.Floor(marker.Position.X), (float)Math.Floor(marker.Position.Y), (float)Math.Floor(marker.Position.Z)),
                        InternalName = name,
                        ActorSNO = marker.NameHash,
                        RActorGuid = marker.MinimapTexture,
                        Distance = marker.Position.Distance(Player.Position),
                        ActorType = ActorType.Item,
                        Type = TrinityObjectType.Item,
                        ItemQuality = ItemQuality.Legendary,
                        Radius = 2f,
                        Weight = 50,
                        IsMarker = true
                    };
                    cacheObject.ObjectHash = HashGenerator.GenerateItemHash(cacheObject);

                    if (GenericBlacklist.ContainsKey(cacheObject.ObjectHash))
                    {
                        Logger.LogDebug(LogCategory.CacheManagement, "Ignoring Marker because it's blacklisted {0} {1} at {2} distance {3}", name, marker.MinimapTexture, marker.Position, marker.Position.Distance(Player.Position));
                        continue;
                    }

                    Logger.LogDebug(LogCategory.CacheManagement, "Adding {0} {1} at {2} distance {3}", name, marker.MinimapTexture, marker.Position, marker.Position.Distance(Player.Position));
                    ObjectCache.Add(cacheObject);
                }

                if (legendaryItemMarkers.Any() && TrinityItemManager.FindValidBackpackLocation(true) != new Vector2(-1, -1))
                {
                    var legendaryItems = ZetaDia.Actors.GetActorsOfType<DiaItem>().Where(i => i.IsValid && i.IsACDBased && i.Position.Distance2D(ZetaDia.Me.Position) < 5f &&
                        legendaryItemMarkers.Any(im => i.Position.Distance2D(i.Position) < 2f));

                    foreach (var diaItem in legendaryItems)
                    {
                        Logger.LogDebug(LogCategory.CacheManagement, "Adding Legendary Item from Marker {0} dist={1} ActorSNO={2} ACD={3} RActor={4}",
                            diaItem.Name, diaItem.Distance, diaItem.ActorSNO, diaItem.ACDGuid, diaItem.RActorGuid);

                        ObjectCache.Add(new TrinityCacheObject()
                        {
                            Position = diaItem.Position,
                            InternalName = diaItem.Name,
                            RActorGuid = diaItem.RActorGuid,
                            ActorSNO = diaItem.ActorSNO,
                            ACDGuid = diaItem.ACDGuid,
                            HasBeenNavigable = true,
                            HasBeenInLoS = true,
                            Distance = diaItem.Distance,
                            ActorType = ActorType.Item,
                            Type = TrinityObjectType.Item,
                            Radius = 2f,
                            Weight = 50,
                            ItemQuality = ItemQuality.Legendary,
                        });
                    }
                }
            }

            bool isRiftGuardianQuestStep = ZetaDia.CurrentQuest.QuestSNO == 337492 && ZetaDia.CurrentQuest.StepId == 16;

            if (isRiftGuardianQuestStep)
            {
                // Add Rift Guardian POI's or Markers to ObjectCache
                const int riftGuardianMarkerTexture = 81058;
                Func<MinimapMarker, bool> riftGuardianMarkerFunc = m => m.IsValid && (m.IsPointOfInterest || m.MinimapTexture == riftGuardianMarkerTexture) &&
                    !Blacklist60Seconds.Contains(m.NameHash);

                foreach (var marker in ZetaDia.Minimap.Markers.CurrentWorldMarkers.Where(riftGuardianMarkerFunc))
                {
                    Logger.LogDebug(LogCategory.CacheManagement, "Adding Rift Guardian POI, distance {0}", marker.Position.Distance2D(Player.Position));
                    ObjectCache.Add(new TrinityCacheObject()
                    {
                        Position = marker.Position,
                        InternalName = "Rift Guardian",
                        Distance = marker.Position.Distance(Player.Position),
                        RActorGuid = marker.NameHash,
                        ActorType = ActorType.Monster,
                        Type = TrinityObjectType.Unit,
                        Radius = 10f,
                        Weight = 5000,
                    });
                }
            }

            if (isRiftGuardianQuestStep || Player.ParticipatingInTieredLootRun) // X1_LR_DungeonFinder
            {
                foreach (var marker in ZetaDia.Minimap.Markers.CurrentWorldMarkers.Where(m => m.IsPointOfInterest && !Blacklist60Seconds.Contains(m.NameHash)))
                {
                    ObjectCache.Add(new TrinityCacheObject()
                    {
                        Position = marker.Position,
                        InternalName = "Rift Guardian",
                        Distance = marker.Position.Distance(Player.Position),
                        RActorGuid = marker.NameHash,
                        ActorType = ActorType.Monster,
                        Type = TrinityObjectType.Unit,
                        Radius = 10f,
                        Weight = 5000,
                    });
                }
            }
        }
Beispiel #27
0
 internal static bool CacheObjectIsInHotSpot(TrinityCacheObject cacheObject)
 {
     return LocationIsInHotSpot(cacheObject.Position, Trinity.Player.WorldID);
 }
Beispiel #28
0
        private static void RefreshWaitTimers()
        {

            // See if we should wait for [playersetting] milliseconds for possible loot drops before continuing run
            if (CurrentTarget == null &&
                (DateTime.UtcNow.Subtract(lastHadUnitInSights).TotalMilliseconds <= Settings.Combat.Misc.DelayAfterKill ||
                DateTime.UtcNow.Subtract(lastHadEliteUnitInSights).TotalMilliseconds <= Settings.Combat.Misc.DelayAfterKill ||
                DateTime.UtcNow.Subtract(lastHadBossUnitInSights).TotalMilliseconds <= 3000 ||
                DateTime.UtcNow.Subtract(Composites.LastFoundHoradricCache).TotalMilliseconds <= 5000) ||
                DateTime.UtcNow.Subtract(lastHadContainerInSights).TotalMilliseconds <= Settings.WorldObject.OpenContainerDelay)
            {
                CurrentTarget = new TrinityCacheObject()
                                    {
                                        Position = Player.Position,
                                        Type = TrinityObjectType.Avoidance,
                                        Weight = 20000,
                                        Distance = 2f,
                                        Radius = 2f,
                                        InternalName = "WaitForLootDrops"
                                    };
                Logger.Log(TrinityLogLevel.Debug, LogCategory.Behavior, "Waiting for loot to drop, delay: {0}ms", Settings.Combat.Misc.DelayAfterKill);
            }

            // End of backtracking check
            // Finally, a special check for waiting for wrath of the berserker cooldown before engaging Azmodan
            if (CurrentTarget == null && Hotbar.Contains(SNOPower.Barbarian_WrathOfTheBerserker) && Settings.Combat.Barbarian.WaitWOTB && !SNOPowerUseTimer(SNOPower.Barbarian_WrathOfTheBerserker) &&
                Player.WorldID == 121214 &&
                (Vector3.Distance(Player.Position, new Vector3(711.25f, 716.25f, 80.13903f)) <= 40f || Vector3.Distance(Player.Position, new Vector3(546.8467f, 551.7733f, 1.576313f)) <= 40f))
            {
                DisableOutofCombatSprint = true;
                BarbarianCombat.AllowSprintOOC = false;
                Logger.Log("[Trinity] Waiting for Wrath Of The Berserker cooldown before continuing to Azmodan.");
                CurrentTarget = new TrinityCacheObject()
                                    {
                                        Position = Player.Position,
                                        Type = TrinityObjectType.Avoidance,
                                        Weight = 20000,
                                        Distance = 2f,
                                        Radius = 2f,
                                        InternalName = "WaitForWrath"
                                    };
            }
            // And a special check for wizard archon
            if (CurrentTarget == null && Hotbar.Contains(SNOPower.Wizard_Archon) && !SNOPowerUseTimer(SNOPower.Wizard_Archon) && Settings.Combat.Wizard.WaitArchon && Player.WorldID == 121214 &&
                (Vector3.Distance(Player.Position, new Vector3(711.25f, 716.25f, 80.13903f)) <= 40f || Vector3.Distance(Player.Position, new Vector3(546.8467f, 551.7733f, 1.576313f)) <= 40f))
            {
                Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation, "Waiting for Wizard Archon cooldown before continuing to Azmodan.");
                CurrentTarget = new TrinityCacheObject()
                                    {
                                        Position = Player.Position,
                                        Type = TrinityObjectType.Avoidance,
                                        Weight = 20000,
                                        Distance = 2f,
                                        Radius = 2f,
                                        InternalName = "WaitForArchon"
                                    };
            }
            // And a very sexy special check for WD BigBadVoodoo
            if (CurrentTarget == null && Hotbar.Contains(SNOPower.Witchdoctor_BigBadVoodoo) && !PowerManager.CanCast(SNOPower.Witchdoctor_BigBadVoodoo) && Player.WorldID == 121214 &&
                (Vector3.Distance(Player.Position, new Vector3(711.25f, 716.25f, 80.13903f)) <= 40f || Vector3.Distance(Player.Position, new Vector3(546.8467f, 551.7733f, 1.576313f)) <= 40f))
            {
                Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation, "Waiting for WD BigBadVoodoo cooldown before continuing to Azmodan.");
                CurrentTarget = new TrinityCacheObject()
                                    {
                                        Position = Player.Position,
                                        Type = TrinityObjectType.Avoidance,
                                        Weight = 20000,
                                        Distance = 2f,
                                        Radius = 2f,
                                        InternalName = "WaitForVoodooo"
                                    };
            }
        }
        private static void RefreshDoBackTrack()
        {
            // See if we should wait for [playersetting] milliseconds for possible loot drops before continuing run
            if (CurrentTarget == null &&
                (DateTime.UtcNow.Subtract(lastHadUnitInSights).TotalMilliseconds <= Settings.Combat.Misc.DelayAfterKill ||
                 DateTime.UtcNow.Subtract(lastHadEliteUnitInSights).TotalMilliseconds <= Settings.Combat.Misc.DelayAfterKill ||
                 DateTime.UtcNow.Subtract(lastHadBossUnitInSights).TotalMilliseconds <= 3000 ||
                 DateTime.UtcNow.Subtract(Helpers.Composites.LastFoundHoradricCache).TotalMilliseconds <= 5000) ||
                DateTime.UtcNow.Subtract(lastHadContainerInSights).TotalMilliseconds <= Settings.WorldObject.OpenContainerDelay)
            {
                CurrentTarget = new TrinityCacheObject()
                {
                    Position     = Player.Position,
                    Type         = GObjectType.Avoidance,
                    Weight       = 20000,
                    Distance     = 2f,
                    Radius       = 2f,
                    InternalName = "WaitForLootDrops"
                };
                Logger.Log(TrinityLogLevel.Debug, LogCategory.Behavior, "Waiting for loot to drop, delay: {0}ms", Settings.Combat.Misc.DelayAfterKill);
            }

            // End of backtracking check
            // Finally, a special check for waiting for wrath of the berserker cooldown before engaging Azmodan
            if (CurrentTarget == null && Hotbar.Contains(SNOPower.Barbarian_WrathOfTheBerserker) && Settings.Combat.Barbarian.WaitWOTB && !SNOPowerUseTimer(SNOPower.Barbarian_WrathOfTheBerserker) &&
                ZetaDia.CurrentWorldId == 121214 &&
                (Vector3.Distance(Player.Position, new Vector3(711.25f, 716.25f, 80.13903f)) <= 40f || Vector3.Distance(Player.Position, new Vector3(546.8467f, 551.7733f, 1.576313f)) <= 40f))
            {
                DisableOutofCombatSprint       = true;
                BarbarianCombat.AllowSprintOOC = false;
                Logger.Log("[Trinity] Waiting for Wrath Of The Berserker cooldown before continuing to Azmodan.");
                CurrentTarget = new TrinityCacheObject()
                {
                    Position     = Player.Position,
                    Type         = GObjectType.Avoidance,
                    Weight       = 20000,
                    Distance     = 2f,
                    Radius       = 2f,
                    InternalName = "WaitForWrath"
                };
            }
            // And a special check for wizard archon
            if (CurrentTarget == null && Hotbar.Contains(SNOPower.Wizard_Archon) && !SNOPowerUseTimer(SNOPower.Wizard_Archon) && Settings.Combat.Wizard.WaitArchon && ZetaDia.CurrentWorldId == 121214 &&
                (Vector3.Distance(Player.Position, new Vector3(711.25f, 716.25f, 80.13903f)) <= 40f || Vector3.Distance(Player.Position, new Vector3(546.8467f, 551.7733f, 1.576313f)) <= 40f))
            {
                Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation, "Waiting for Wizard Archon cooldown before continuing to Azmodan.");
                CurrentTarget = new TrinityCacheObject()
                {
                    Position     = Player.Position,
                    Type         = GObjectType.Avoidance,
                    Weight       = 20000,
                    Distance     = 2f,
                    Radius       = 2f,
                    InternalName = "WaitForArchon"
                };
            }
            // And a very sexy special check for WD BigBadVoodoo
            if (CurrentTarget == null && Hotbar.Contains(SNOPower.Witchdoctor_BigBadVoodoo) && !PowerManager.CanCast(SNOPower.Witchdoctor_BigBadVoodoo) && ZetaDia.CurrentWorldId == 121214 &&
                (Vector3.Distance(Player.Position, new Vector3(711.25f, 716.25f, 80.13903f)) <= 40f || Vector3.Distance(Player.Position, new Vector3(546.8467f, 551.7733f, 1.576313f)) <= 40f))
            {
                Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation, "Waiting for WD BigBadVoodoo cooldown before continuing to Azmodan.");
                CurrentTarget = new TrinityCacheObject()
                {
                    Position     = Player.Position,
                    Type         = GObjectType.Avoidance,
                    Weight       = 20000,
                    Distance     = 2f,
                    Radius       = 2f,
                    InternalName = "WaitForVoodooo"
                };
            }
        }
Beispiel #30
0
 /// <summary>
 /// Initializes variable set for single object refresh
 /// </summary>
 private static void RefreshStepInit()
 {
     CurrentCacheObject = new TrinityCacheObject();
     // Start this object as off as unknown type
     CurrentCacheObject.Type = TrinityObjectType.Unknown;
     CurrentCacheObject.GizmoType = GizmoType.None;
     CurrentCacheObject.Distance = 0f;
     CurrentCacheObject.Radius = 0f;
     c_ZDiff = 0f;
     c_ItemDisplayName = "";
     c_ItemLink = "";
     CurrentCacheObject.InternalName = "";
     c_IgnoreReason = "";
     c_IgnoreSubStep = "";
     CurrentCacheObject.ACDGuid = -1;
     CurrentCacheObject.RActorGuid = -1;
     CurrentCacheObject.DynamicID = -1;
     CurrentCacheObject.GameBalanceID = -1;
     CurrentCacheObject.ActorSNO = -1;
     c_ItemLevel = -1;
     c_GoldStackSize = -1;
     c_HitPointsPct = -1;
     c_HitPoints = -1;
     c_IsOneHandedItem = false;
     c_IsTwoHandedItem = false;
     c_unit_IsElite = false;
     c_unit_IsRare = false;
     c_unit_IsUnique = false;
     c_unit_IsMinion = false;
     c_unit_IsTreasureGoblin = false;
     c_unit_IsAttackable = false;
     c_unit_HasShieldAffix = false;
     c_IsEliteRareUnique = false;
     c_IsObstacle = false;
     c_HasBeenNavigable = false;
     c_HasBeenRaycastable = false;
     c_HasBeenInLoS = false;
     c_ItemMd5Hash = string.Empty;
     c_ItemQuality = ItemQuality.Invalid;
     c_DBItemBaseType = ItemBaseType.None;
     c_DBItemType = ItemType.Unknown;
     c_item_tFollowerType = FollowerType.None;
     _cItemTinityItemType = TrinityItemType.Unknown;
     c_unit_MonsterSize = MonsterSize.Unknown;
     c_diaObject = null;
     c_diaGizmo = null;
     c_CurrentAnimation = SNOAnim.Invalid;
     c_HasDotDPS = false;
     c_MonsterAffixes = MonsterAffixes.None;
 }
Beispiel #31
0
        private static void RefreshSetKiting(ref Vector3 vKitePointAvoid, bool NeedToKite)
        {
            using (new PerformanceLogger("RefreshDiaObjectCache.Kiting"))
            {

                bool TryToKite = false;

                List<TrinityCacheObject> kiteMonsterList = new List<TrinityCacheObject>();

                if (CurrentTarget != null && CurrentTarget.IsUnit)
                {
                    switch (CombatBase.KiteMode)
                    {
                        case KiteMode.Never:
                            break;
                        case KiteMode.Elites:
                            kiteMonsterList = (from m in ObjectCache
                                               where m.IsUnit &&
                                               m.RadiusDistance > 0 &&
                                               m.RadiusDistance <= CombatBase.KiteDistance &&
                                               m.IsBossOrEliteRareUnique
                                               select m).ToList();
                            break;
                        case KiteMode.Bosses:
                            kiteMonsterList = (from m in ObjectCache
                                               where m.IsUnit &&
                                               m.RadiusDistance > 0 &&
                                               m.RadiusDistance <= CombatBase.KiteDistance &&
                                               m.IsBoss
                                               select m).ToList();
                            break;
                        case KiteMode.Always:
                            kiteMonsterList = (from m in ObjectCache
                                               where m.IsUnit &&
                                               m.Weight > 0 &&
                                               m.RadiusDistance > 0 &&
                                               m.RadiusDistance <= CombatBase.KiteDistance &&
                                               (m.IsBossOrEliteRareUnique ||
                                                ((m.HitPointsPct >= .15 || m.MonsterSize != MonsterSize.Swarm) && !m.IsBossOrEliteRareUnique))
                                               select m).ToList();
                            break;
                    }
                }
                if (kiteMonsterList.Any())
                {
                    TryToKite = true;
                    vKitePointAvoid = Player.Position;
                }

                if (CombatBase.KiteDistance > 0 && kiteMonsterList.Count() > 0 && IsWizardShouldKite())
                {
                    TryToKite = true;
                    vKitePointAvoid = Player.Position;
                }

                // Avoid Death
                if (Settings.Combat.Misc.AvoidDeath &&
                    Player.CurrentHealthPct <= CombatBase.EmergencyHealthPotionLimit && // health is lower than potion limit
                    !SNOPowerUseTimer(SNOPower.DrinkHealthPotion) && // we can't use a potion anymore
                    TargetUtil.AnyMobsInRange(90f, false))
                {
                    Logger.LogNormal("Attempting to avoid death!");
                    NeedToKite = true;

                    kiteMonsterList = (from m in ObjectCache
                                       where m.IsUnit
                                       select m).ToList();
                }

                // Note that if treasure goblin level is set to kamikaze, even avoidance moves are disabled to reach the goblin!
                bool shouldKamikazeTreasureGoblins = (!AnyTreasureGoblinsPresent || Settings.Combat.Misc.GoblinPriority <= GoblinPriority.Prioritize);

                double msCancelledEmergency = DateTime.UtcNow.Subtract(timeCancelledEmergencyMove).TotalMilliseconds;
                bool shouldEmergencyMove = msCancelledEmergency >= cancelledEmergencyMoveForMilliseconds && NeedToKite;

                double msCancelledKite = DateTime.UtcNow.Subtract(timeCancelledKiteMove).TotalMilliseconds;
                bool shouldKite = msCancelledKite >= cancelledKiteMoveForMilliseconds && TryToKite;

                if (shouldKamikazeTreasureGoblins && (shouldEmergencyMove || shouldKite))
                {
                    Vector3 vAnySafePoint = NavHelper.FindSafeZone(false, 1, vKitePointAvoid, true, kiteMonsterList, shouldEmergencyMove);

                    if (LastKitePosition == null)
                    {
                        LastKitePosition = new KitePosition()
                        {
                            PositionFoundTime = DateTime.UtcNow,
                            Position = vAnySafePoint,
                            Distance = vAnySafePoint.Distance(Player.Position)
                        };
                    }

                    if (vAnySafePoint != Vector3.Zero && vAnySafePoint.Distance(Player.Position) >= 1)
                    {

                        if ((DateTime.UtcNow.Subtract(LastKitePosition.PositionFoundTime).TotalMilliseconds > 3000 && LastKitePosition.Position == vAnySafePoint) ||
                            (CurrentTarget != null && DateTime.UtcNow.Subtract(lastGlobalCooldownUse).TotalMilliseconds > 1500 && TryToKite))
                        {
                            timeCancelledKiteMove = DateTime.UtcNow;
                            cancelledKiteMoveForMilliseconds = 1500;
                            Logger.Log(TrinityLogLevel.Debug, LogCategory.UserInformation, "Kite movement failed, cancelling for {0:0}ms", cancelledKiteMoveForMilliseconds);
                            return;
                        }
                        else
                        {
                            LastKitePosition = new KitePosition()
                            {
                                PositionFoundTime = DateTime.UtcNow,
                                Position = vAnySafePoint,
                                Distance = vAnySafePoint.Distance(Player.Position)
                            };
                        }

                        if (Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement))
                        {
                            Logger.Log(TrinityLogLevel.Verbose, LogCategory.Movement, "Kiting to: {0} Distance: {1:0} Direction: {2:0}, Health%={3:0.00}, KiteDistance: {4:0}, Nearby Monsters: {5:0} NeedToKite: {6} TryToKite: {7}",
                                vAnySafePoint, vAnySafePoint.Distance(Player.Position), MathUtil.GetHeading(MathUtil.FindDirectionDegree(Me.Position, vAnySafePoint)),
                                Player.CurrentHealthPct, CombatBase.KiteDistance, kiteMonsterList.Count(),
                                NeedToKite, TryToKite);
                        }
                        CurrentTarget = new TrinityCacheObject()
                        {
                            Position = vAnySafePoint,
                            Type = TrinityObjectType.Avoidance,
                            Weight = 90000,
                            Distance = Vector3.Distance(Player.Position, vAnySafePoint),
                            Radius = 2f,
                            InternalName = "KitePoint"
                        };
                    }
                }
                else if (!shouldEmergencyMove && NeedToKite)
                {
                    Logger.Log(TrinityLogLevel.Debug, LogCategory.UserInformation, "Emergency movement cancelled for {0:0}ms", DateTime.UtcNow.Subtract(timeCancelledEmergencyMove).TotalMilliseconds - cancelledKiteMoveForMilliseconds);
                }
                else if (!shouldKite && TryToKite)
                {
                    Logger.Log(TrinityLogLevel.Debug, LogCategory.UserInformation, "Kite movement cancelled for {0:0}ms", DateTime.UtcNow.Subtract(timeCancelledKiteMove).TotalMilliseconds - cancelledKiteMoveForMilliseconds);
                }
            }
        }
Beispiel #32
0
        internal static List<TrinityCacheObject> GetCacheObjectHotSpots()
        {
            List<TrinityCacheObject> list = new List<TrinityCacheObject>();

            if (Trinity.Player.IsInTown)
                return list;

            var hotSpotList = HotSpotList.Where(s => 
                s.Location.Distance2D(Trinity.Player.Position) <= V.F("Cache.HotSpot.MaxDistance") && 
                s.Location.Distance2D(Trinity.Player.Position) >= V.F("Cache.HotSpot.MinDistance") && 
                s.WorldId == Trinity.Player.WorldID).ToList();

            foreach (var hotSpot in hotSpotList)
            {
                Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Adding HotSpot to Cache: {0}", hotSpot);
                var o = new TrinityCacheObject()
                {
                    Position = hotSpot.Location,
                    InternalName = "HotSpot",
                    Type = TrinityObjectType.HotSpot,
                    Distance = Trinity.Player.Position.Distance2D(hotSpot.Location),
                    Radius = HotSpot.MaxPositionDistance,
                };

                list.Add(o);
            }

            return list;
        }
        /// <summary>
        /// This method will add and update necessary information about all available actors. Determines ObjectType, sets ranges, updates blacklists, determines avoidance, kiting, target weighting
        /// and the result is we will have a new target for the Target Handler. Returns true if the cache was refreshed.
        /// </summary>
        /// <returns>True if the cache was updated</returns>
        public static bool RefreshDiaObjectCache(bool forceUpdate = false)
        {
            using (new PerformanceLogger("RefreshDiaObjectCache"))
            {
                if (DateTime.UtcNow.Subtract(LastRefreshedCache).TotalMilliseconds < Settings.Advanced.CacheRefreshRate && !forceUpdate)
                {
                    if (!UpdateCurrentTarget())
                    {
                        return(false);
                    }
                }
                LastRefreshedCache = DateTime.UtcNow;

                using (new PerformanceLogger("RefreshDiaObjectCache.UpdateBlock"))
                {
                    CacheData.Clear();
                    GenericCache.MaintainCache();
                    GenericBlacklist.MaintainBlacklist();

                    // Update player-data cache, including buffs
                    PlayerInfoCache.UpdateCachedPlayerData();

                    if (Player.CurrentHealthPct <= 0)
                    {
                        return(false);
                    }

                    RefreshCacheInit();

                    // Now pull up all the data and store anything we want to handle in the super special cache list
                    // Also use many cache dictionaries to minimize DB<->D3 memory hits, and speed everything up a lot
                    RefreshCacheMainLoop();
                }

                // Add Team HotSpots to the cache
                ObjectCache.AddRange(GroupHotSpots.GetCacheObjectHotSpots());

                /* Fire Chains Experimental Avoidance */
                if (Settings.Combat.Misc.UseExperimentalFireChainsAvoidance)
                {
                    const float fireChainSize = 5f;
                    foreach (var unit1 in ObjectCache.Where(u => u.MonsterAffixes.HasFlag(MonsterAffixes.FireChains)))
                    {
                        foreach (var unit2 in ObjectCache.Where(u => u.MonsterAffixes.HasFlag(MonsterAffixes.FireChains)).Where(unit2 => unit1.RActorGuid != unit2.RActorGuid))
                        {
                            for (float i = 0; i <= unit1.Position.Distance2D(unit2.Position); i += (fireChainSize / 4))
                            {
                                Vector3 fireChainSpot = MathEx.CalculatePointFrom(unit1.Position, unit2.Position, i);

                                if (Trinity.Player.Position.Distance2D(fireChainSpot) <= fireChainSize)
                                {
                                    Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Avoiding Fire Chains!");
                                    _standingInAvoidance = true;
                                }
                                CacheData.TimeBoundAvoidance.Add(new CacheObstacleObject(fireChainSpot, fireChainSize, -2, "FireChains"));
                            }
                        }
                        if (CacheData.TimeBoundAvoidance.Any(aoe => aoe.ActorSNO == -2))
                        {
                            Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Generated {0} avoidance points for FireChains, minDistance={1} maxDistance={2}",
                                       CacheData.TimeBoundAvoidance.Count(aoe => aoe.ActorSNO == -2),
                                       CacheData.TimeBoundAvoidance.Where(aoe => aoe.ActorSNO == -2)
                                       .Min(aoe => aoe.Position.Distance2D(Trinity.Player.Position)),
                                       CacheData.TimeBoundAvoidance.Where(aoe => aoe.ActorSNO == -2)
                                       .Max(aoe => aoe.Position.Distance2D(Trinity.Player.Position)));
                        }
                    }
                }

                /* Beast Charge Experimental Avoidance */
                if (Settings.Combat.Misc.UseExperimentalSavageBeastAvoidance)
                {
                    const float beastChargePathWidth = 10f;
                    const int   beastChargerSNO      = 3337;
                    foreach (var unit1 in ObjectCache.Where(u => u.IsFacingPlayer && u.Animation == SNOAnim.Beast_start_charge_02 ||
                                                            u.Animation == SNOAnim.Beast_charge_02 || u.Animation == SNOAnim.Beast_charge_04))
                    {
                        Vector3 endPoint = MathEx.GetPointAt(unit1.Position, 90f, unit1.Unit.Movement.Rotation);

                        for (float i = 0; i <= unit1.Position.Distance2D(endPoint); i += (beastChargePathWidth / 4))
                        {
                            Vector3 pathSpot = MathEx.CalculatePointFrom(unit1.Position, endPoint, i);

                            Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement,
                                       "Generating BeastCharge Avoidance: {0} dist: {1}",
                                       pathSpot, pathSpot.Distance2D(unit1.Position));

                            if (Trinity.Player.Position.Distance2D(pathSpot) <= beastChargePathWidth)
                            {
                                Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Avoiding Beast Charger!");
                                _standingInAvoidance = true;
                            }
                            CacheData.TimeBoundAvoidance.Add(new CacheObstacleObject(pathSpot, beastChargePathWidth, beastChargerSNO,
                                                                                     "BeastCharge"));
                        }
                        if (CacheData.TimeBoundAvoidance.Any(aoe => aoe.ActorSNO == beastChargerSNO))
                        {
                            Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement,
                                       "Generated {0} avoidance points for BeastCharge, minDistance={1} maxDistance={2}",
                                       CacheData.TimeBoundAvoidance.Count(aoe => aoe.ActorSNO == beastChargerSNO),
                                       CacheData.TimeBoundAvoidance.Where(aoe => aoe.ActorSNO == beastChargerSNO)
                                       .Min(aoe => aoe.Position.Distance2D(Trinity.Player.Position)),
                                       CacheData.TimeBoundAvoidance.Where(aoe => aoe.ActorSNO == beastChargerSNO)
                                       .Max(aoe => aoe.Position.Distance2D(Trinity.Player.Position)));
                        }
                    }
                }

                /* Poison Experimental Avoidance */



                // Reduce ignore-for-loops counter
                if (_ignoreTargetForLoops > 0)
                {
                    _ignoreTargetForLoops--;
                }
                // If we have an avoidance under our feet, then create a new object which contains a safety point to move to
                // But only if we aren't force-cancelling avoidance for XX time
                bool hasFoundSafePoint = false;

                using (new PerformanceLogger("RefreshDiaObjectCache.AvoidanceCheck"))
                {
                    if (Player.IsGhosted)
                    {
                        _standingInAvoidance = true;
                    }

                    // Note that if treasure goblin level is set to kamikaze, even avoidance moves are disabled to reach the goblin!
                    if (_standingInAvoidance && (!AnyTreasureGoblinsPresent || Settings.Combat.Misc.GoblinPriority <= GoblinPriority.Prioritize) &&
                        DateTime.UtcNow.Subtract(timeCancelledEmergencyMove).TotalMilliseconds >= cancelledEmergencyMoveForMilliseconds)
                    {
                        Vector3 vAnySafePoint = NavHelper.FindSafeZone(false, 1, Player.Position, true, null, true);

                        // Ignore avoidance stuff if we're incapacitated or didn't find a safe spot we could reach
                        if (vAnySafePoint != Vector3.Zero)
                        {
                            if (Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement))
                            {
                                Logger.Log(TrinityLogLevel.Verbose, LogCategory.Movement, "Kiting Avoidance: {0} Distance: {1:0} Direction: {2:0}, Health%={3:0.00}, KiteDistance: {4:0}",
                                           vAnySafePoint, vAnySafePoint.Distance(Me.Position), MathUtil.GetHeading(MathUtil.FindDirectionDegree(Me.Position, vAnySafePoint)),
                                           Player.CurrentHealthPct, CombatBase.PlayerKiteDistance);
                            }

                            hasFoundSafePoint = true;
                            CurrentTarget     = new TrinityCacheObject()
                            {
                                Position     = vAnySafePoint,
                                Type         = GObjectType.Avoidance,
                                Weight       = 20000,
                                Distance     = Vector3.Distance(Player.Position, vAnySafePoint),
                                Radius       = 2f,
                                InternalName = "SafePoint"
                            };;
                        }
                    }
                }

                /*
                 *  Set Weights, assign CurrentTarget
                 */

                if (!hasFoundSafePoint)
                {
                    RefreshDiaGetWeights();

                    RefreshSetKiting(ref KiteAvoidDestination, NeedToKite);
                }
                // Not heading straight for a safe-spot?
                // No valid targets but we were told to stay put?
                if (CurrentTarget == null && _shouldStayPutDuringAvoidance && !_standingInAvoidance)
                {
                    CurrentTarget = new TrinityCacheObject()
                    {
                        Position     = Player.Position,
                        Type         = GObjectType.Avoidance,
                        Weight       = 20000,
                        Distance     = 2f,
                        Radius       = 2f,
                        InternalName = "StayPutPoint"
                    };
                    Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Staying Put During Avoidance");
                }

                // Pre-townrun is too far away
                if (!Player.IsInTown && TownRun.PreTownRunPosition != Vector3.Zero && TownRun.PreTownRunWorldId == Player.WorldID && !ForceVendorRunASAP &&
                    TownRun.PreTownRunPosition.Distance2D(Player.Position) <= V.F("Cache.PretownRun.MaxDistance"))
                {
                    Logger.Log(TrinityLogLevel.Debug, LogCategory.UserInformation, "Pre-TownRun position is more than {0} yards away, canceling", V.I("Cache.PretownRun.MaxDistance"));
                    TownRun.PreTownRunPosition = Vector3.Zero;
                    TownRun.PreTownRunWorldId  = -1;
                }

                // Reached pre-townrun position
                if (!Player.IsInTown && TownRun.PreTownRunPosition != Vector3.Zero && TownRun.PreTownRunWorldId == Player.WorldID && !ForceVendorRunASAP &&
                    TownRun.PreTownRunPosition.Distance2D(Player.Position) <= 15f)
                {
                    Logger.Log(TrinityLogLevel.Debug, LogCategory.UserInformation, "Successfully returned to Pre-TownRun Position");
                    TownRun.PreTownRunPosition = Vector3.Zero;
                    TownRun.PreTownRunWorldId  = -1;
                }

                // After a townrun, make sure to return to original TownRun Location
                if (!Player.IsInTown && CurrentTarget == null && TownRun.PreTownRunPosition != Vector3.Zero && TownRun.PreTownRunWorldId == Player.WorldID && !ForceVendorRunASAP)
                {
                    if (TownRun.PreTownRunPosition.Distance2D(Player.Position) > 10f && TownRun.PreTownRunPosition.Distance2D(Player.Position) <= V.F("Cache.PretownRun.MaxDistance"))
                    {
                        CurrentTarget = new TrinityCacheObject()
                        {
                            Position     = TownRun.PreTownRunPosition,
                            Type         = GObjectType.Avoidance,
                            Weight       = 20000,
                            Distance     = 2f,
                            Radius       = 2f,
                            InternalName = "PreTownRunPosition"
                        };
                        Logger.Log(TrinityLogLevel.Debug, LogCategory.UserInformation, "Returning to Pre-TownRun Position");
                    }
                }

                using (new PerformanceLogger("RefreshDiaObjectCache.FinalChecks"))
                {
                    // force to stay put if we want to town run and there's no target
                    if (CurrentTarget == null && ForceVendorRunASAP)
                    {
                        DontMoveMeIAmDoingShit = true;
                    }

                    if (Settings.WorldObject.EnableBountyEvents)
                    {
                        bool eventObjectNear = ObjectCache.Any(o => o.Type == GObjectType.CursedChest || o.Type == GObjectType.CursedShrine);

                        if (!Player.InActiveEvent)
                        {
                            EventStartPosition = Vector3.Zero;
                            EventStartTime     = DateTime.MinValue;
                        }

                        // Reset Event time while we have targts
                        if (CurrentTarget != null && Player.InActiveEvent && eventObjectNear)
                        {
                            EventStartTime = DateTime.UtcNow;
                        }

                        if (eventObjectNear)
                        {
                            EventStartPosition = ObjectCache.FirstOrDefault(o => o.Type == GObjectType.CursedChest || o.Type == GObjectType.CursedShrine).Position;
                        }

                        var activeEvent = ZetaDia.ActInfo.ActiveQuests.FirstOrDefault(q => DataDictionary.EventQuests.Contains(q.QuestSNO));

                        const int waitTimeoutSeconds = 90;
                        if (DateTime.UtcNow.Subtract(EventStartTime).TotalSeconds > waitTimeoutSeconds && activeEvent != null)
                        {
                            CacheData.BlacklistedEvents.Add(activeEvent.QuestSNO);
                        }

                        if (CurrentTarget == null && Player.InActiveEvent && EventStartPosition != Vector3.Zero &&
                            DateTime.UtcNow.Subtract(EventStartTime).TotalSeconds < waitTimeoutSeconds &&
                            activeEvent != null && !CacheData.BlacklistedEvents.Contains(activeEvent.QuestSNO))
                        {
                            CurrentTarget = new TrinityCacheObject()
                            {
                                Position     = EventStartPosition,
                                Type         = GObjectType.Avoidance,
                                Weight       = 20000,
                                Distance     = 2f,
                                Radius       = 2f,
                                InternalName = "WaitForEvent"
                            };
                            Logger.Log("Waiting for Event {0} - Time Remaining: {1:0} seconds",
                                       ZetaDia.ActInfo.ActiveQuests.FirstOrDefault(q => DataDictionary.EventQuests.Contains(q.QuestSNO)).Quest,
                                       waitTimeoutSeconds - DateTime.UtcNow.Subtract(EventStartTime).TotalSeconds);
                        }
                    }

                    // Still no target, let's see if we should backtrack or wait for wrath to come off cooldown...
                    if (CurrentTarget == null)
                    {
                        RefreshDoBackTrack();
                    }

                    // Still no target, let's end it all!
                    if (CurrentTarget == null)
                    {
                        return(true);
                    }


                    if (CurrentTarget.IsUnit)
                    {
                        lastHadUnitInSights = DateTime.UtcNow;
                    }

                    if (CurrentTarget.IsBossOrEliteRareUnique)
                    {
                        lastHadEliteUnitInSights = DateTime.UtcNow;
                    }

                    if (CurrentTarget.IsBoss || CurrentTarget.IsBountyObjective)
                    {
                        lastHadBossUnitInSights = DateTime.UtcNow;
                    }


                    if (CurrentTarget.Type == GObjectType.Container)
                    {
                        lastHadContainerInSights = DateTime.UtcNow;
                    }

                    // Record the last time our target changed
                    if (LastTargetRactorGUID != CurrentTarget.RActorGuid)
                    {
                        RecordTargetHistory();

                        Logger.Log(TrinityLogLevel.Verbose, LogCategory.Weight,
                                   "Found New Target {0} dist={1:0} IsElite={2} Radius={3:0.0} Weight={4:0} ActorSNO={5} " +
                                   "Anim={6} TargetedCount={7} Type={8} ",
                                   CurrentTarget.InternalName,
                                   CurrentTarget.Distance,
                                   CurrentTarget.IsEliteRareUnique,
                                   CurrentTarget.Radius,
                                   CurrentTarget.Weight,
                                   CurrentTarget.ActorSNO,
                                   CurrentTarget.Animation,
                                   CurrentTarget.TimesBeenPrimaryTarget,
                                   CurrentTarget.Type
                                   );

                        _lastPickedTargetTime = DateTime.UtcNow;
                        _targetLastHealth     = 0f;
                    }
                    else
                    {
                        // We're sticking to the same target, so update the target's health cache to check for stucks
                        if (CurrentTarget.IsUnit)
                        {
                            // Check if the health has changed, if so update the target-pick time before we blacklist them again
                            if (CurrentTarget.HitPointsPct != _targetLastHealth)
                            {
                                Logger.Log(TrinityLogLevel.Debug, LogCategory.Weight, "Keeping Target {0} - CurrentTarget.HitPoints: {1:0.00} TargetLastHealth: {2:0.00} ",
                                           CurrentTarget.RActorGuid, CurrentTarget.HitPointsPct, _targetLastHealth);
                                _lastPickedTargetTime = DateTime.UtcNow;
                            }
                            // Now store the target's last-known health
                            _targetLastHealth = CurrentTarget.HitPointsPct;
                        }
                    }
                }
                // We have a target and the cached was refreshed
                return(true);
            }
        }