/// <summary> /// Called when user disable the plugin. /// </summary> public void OnDisabled() { _isPluginEnabled = false; BotManager.ReplaceTreeHooks(); Navigator.PlayerMover = new DefaultPlayerMover(); Navigator.StuckHandler = new DefaultStuckHandler(); CombatTargeting.Instance.Provider = new DefaultCombatTargetingProvider(); LootTargeting.Instance.Provider = new DefaultLootTargetingProvider(); ObstacleTargeting.Instance.Provider = new DefaultObstacleTargetingProvider(); Navigator.SearchGridProvider = new MainGridProvider(); GameEvents.OnPlayerDied -= TrinityOnDeath; BotMain.OnStop -= TrinityBotStop; GameEvents.OnPlayerDied -= TrinityOnDeath; GameEvents.OnGameJoined -= TrinityOnJoinGame; GameEvents.OnGameLeft -= TrinityOnLeaveGame; GameEvents.OnItemSold -= ItemEvents.TrinityOnItemSold; GameEvents.OnItemSalvaged -= ItemEvents.TrinityOnItemSalvaged; GameEvents.OnItemStashed -= ItemEvents.TrinityOnItemStashed; GameEvents.OnItemIdentificationRequest -= ItemEvents.TrinityOnOnItemIdentificationRequest; GameEvents.OnGameChanged -= GameEvents_OnGameChanged; GameEvents.OnWorldChanged -= GameEvents_OnWorldChanged; ItemManager.Current = new LootRuleItemManager(); Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation, ""); Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation, "DISABLED: Trinity is now shut down..."); Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation, ""); GenericCache.Shutdown(); GenericBlacklist.Shutdown(); }
public static void ResetEverythingNewGame() { // In-thread stuff V.ValidateLoad(); // Out of thread Async stuff BeginInvoke(new Action(() => { Logger.Log("New Game - resetting everything"); Trinity.IsReadyToTownRun = false; Trinity.ForceVendorRunASAP = false; TownRun.TownRunCheckTimer.Reset(); TownRun.SendEmailNotification(); TownRun.PreTownRunPosition = Vector3.Zero; TownRun.PreTownRunWorldId = -1; TownRun.WasVendoring = false; CacheData.AbilityLastUsed.Clear(); SpellHistory.HistoryQueue.Clear(); DeathsThisRun = 0; LastDeathTime = DateTime.UtcNow; _hashsetItemStatsLookedAt = new HashSet <string>(); _hashsetItemPicksLookedAt = new HashSet <string>(); _hashsetItemFollowersIgnored = new HashSet <string>(); Blacklist60Seconds = new HashSet <int>(); Blacklist90Seconds = new HashSet <int>(); Blacklist15Seconds = new HashSet <int>(); BacktrackList = new SortedList <int, Vector3>(); TotalBacktracks = 0; HasMappedPlayerAbilities = false; PlayerMover.TotalAntiStuckAttempts = 1; PlayerMover.vSafeMovementLocation = Vector3.Zero; PlayerMover.LastPosition = Vector3.Zero; PlayerMover.TimesReachedStuckPoint = 0; PlayerMover.TimeLastRecordedPosition = DateTime.MinValue; PlayerMover.LastGeneratedStuckPosition = DateTime.MinValue; PlayerMover.TimesReachedMaxUnstucks = 0; PlayerMover.CancelUnstuckerForSeconds = 0; PlayerMover.LastCancelledUnstucker = DateTime.MinValue; NavHelper.UsedStuckSpots = new List <GridPoint>(); CacheData.FullClear(); // Reset all the caches ProfileHistory = new List <string>(); CurrentProfile = ""; FirstProfile = ""; Logger.Log("New Game, resetting Gold Inactivity Timer"); GoldInactivity.Instance.ResetCheckGold(); CombatBase.IsQuestingMode = false; GenericCache.ClearCache(); GenericBlacklist.ClearBlacklist(); })); }
private static bool RefreshUnit() { bool addToCache = true; if (!(c_diaObject is DiaUnit)) { return(false); } if (CurrentCacheObject.Unit == null) { return(false); } if (!CurrentCacheObject.Unit.IsValid) { return(false); } if (!CurrentCacheObject.Unit.CommonData.IsValid) { return(false); } if (c_diaObject.CommonData.ACDGuid == -1) { return(false); } // Always set this, otherwise we divide by zero later CurrentCacheObject.KillRange = CurrentBotKillRange; // grab this first c_CurrentAnimation = CurrentCacheObject.Unit.CommonData.CurrentAnimation; // See if this is a boss CurrentCacheObject.IsBoss = DataDictionary.BossIds.Contains(CurrentCacheObject.ActorSNO) || CurrentCacheObject.InternalName.ToLower().Contains("boss") || CurrentCacheObject.CommonData.MonsterQualityLevel == Zeta.Game.Internals.Actors.MonsterQuality.Boss; if (CurrentCacheObject.IsBoss) { CurrentCacheObject.KillRange = CurrentCacheObject.RadiusDistance + 10f; } // hax for Diablo_shadowClone c_unit_IsAttackable = CurrentCacheObject.InternalName.StartsWith("Diablo_shadowClone"); try { if (CurrentCacheObject.Unit.Movement.IsValid) { c_IsFacingPlayer = CurrentCacheObject.Unit.IsFacingPlayer; CurrentCacheObject.Rotation = CurrentCacheObject.Unit.Movement.Rotation; CurrentCacheObject.DirectionVector = CurrentCacheObject.Unit.Movement.DirectionVector; } } catch (Exception ex) { Logger.LogDebug(LogCategory.CacheManagement, "Error while reading Rotation/Facing: {0}", ex.ToString()); } /* * TeamID - check once for all units except bosses (which can potentially change teams - Belial, Cydea) */ string teamIdHash = "teamId.RActorGuid=" + CurrentCacheObject.RActorGuid + ".ActorSNO=" + CurrentCacheObject.ActorSNO + ".WorldId=" + Player.WorldID; int teamId; if (!CurrentCacheObject.IsBoss && GenericCache.ContainsKey(teamIdHash)) { teamId = (int)GenericCache.GetObject(teamIdHash).Value; } else { teamId = CurrentCacheObject.Unit.TeamId; GenericCache.AddToCache(new GenericCacheObject { Key = teamIdHash, Value = teamId, Expires = DateTime.UtcNow.AddMinutes(60) }); } CacheObjectIsBountyObjective(); try { CurrentCacheObject.IsNPC = CurrentCacheObject.Unit.IsNPC; } catch (Exception) { Logger.LogDebug("Error refreshing IsNPC"); } try { CurrentCacheObject.IsSpawning = CurrentCacheObject.IsBoss && !CurrentCacheObject.Unit.IsAttackable; } catch (Exception) { Logger.LogDebug("Error refreshing IsSpawning"); } CacheUnitNPCIsOperatable(); CacheObjectMinimapActive(); try { CurrentCacheObject.IsQuestMonster = CurrentCacheObject.Unit.IsQuestMonster; if (CurrentCacheObject.IsQuestMonster) { CurrentCacheObject.KillRange = CurrentCacheObject.RadiusDistance + 10f; } } catch (Exception ex) { Logger.LogDebug(LogCategory.CacheManagement, "Error reading IsQuestMonster for Unit sno:{0} raGuid:{1} name:{2} ex:{3}", CurrentCacheObject.ActorSNO, CurrentCacheObject.RActorGuid, CurrentCacheObject.InternalName, ex.Message); } try { CurrentCacheObject.IsQuestGiver = CurrentCacheObject.Unit.IsQuestGiver; // Interact with quest givers, except when doing town-runs if (ZetaDia.CurrentAct == Act.OpenWorld && CurrentCacheObject.IsQuestGiver && !(WantToTownRun || ForceVendorRunASAP || BrainBehavior.IsVendoring)) { CurrentCacheObject.Type = TrinityObjectType.Interactable; CurrentCacheObject.Type = TrinityObjectType.Interactable; CurrentCacheObject.Radius = c_diaObject.CollisionSphere.Radius; return(true); } } catch (Exception) { Logger.LogDebug("Error refreshing IsQuestGiver"); } if ((teamId == 1 || teamId == 2 || teamId == 17)) { addToCache = false; c_IgnoreSubStep += "IsTeam" + teamId; return(addToCache); } /* Always refresh monster type */ if (CurrentCacheObject.Type != TrinityObjectType.Player && !CurrentCacheObject.IsBoss) { switch (c_diaObject.CommonData.MonsterInfo.MonsterType) { case MonsterType.Ally: case MonsterType.Scenery: case MonsterType.Helper: case MonsterType.Team: { addToCache = false; c_IgnoreSubStep = "AllySceneryHelperTeam"; return(addToCache); } } } // Only set treasure goblins to true *IF* they haven't disabled goblins! Then check the SNO in the goblin hash list! c_unit_IsTreasureGoblin = false; // Flag this as a treasure goblin *OR* ignore this object altogether if treasure goblins are set to ignore if (DataDictionary.GoblinIds.Contains(CurrentCacheObject.ActorSNO) || CurrentCacheObject.InternalName.ToLower().StartsWith("treasureGoblin")) { if (Settings.Combat.Misc.GoblinPriority != 0) { c_unit_IsTreasureGoblin = true; } else { addToCache = false; c_IgnoreSubStep = "IgnoreTreasureGoblins"; return(addToCache); } } // Pull up the Monster Affix cached data RefreshAffixes(); if (c_MonsterAffixes.HasFlag(MonsterAffixes.Shielding)) { c_unit_HasShieldAffix = true; } // Only if at full health, else don't bother checking each loop // See if we already have this monster's size stored, if not get it and cache it if (!CacheData.MonsterSizes.TryGetValue(CurrentCacheObject.ActorSNO, out c_unit_MonsterSize)) { try { RefreshMonsterSize(); } catch { Logger.LogDebug("Error refreshing MonsterSize"); } } RefreshMonsterHealth(); DebugUtil.LogAnimation(CurrentCacheObject); // Unit is already dead if (c_HitPoints <= 0d && !CurrentCacheObject.IsBoss) { addToCache = false; c_IgnoreSubStep = "0HitPoints"; return(addToCache); } if (CurrentCacheObject.Unit.IsDead && !DataDictionary.FakeDeathMonsters.Contains(CurrentCacheObject.ActorSNO)) { addToCache = false; c_IgnoreSubStep = "IsDead"; return(addToCache); } if (CurrentCacheObject.IsQuestMonster || CurrentCacheObject.IsBountyObjective) { return(true); } addToCache = RefreshUnitAttributes(addToCache, CurrentCacheObject.Unit); if (!addToCache) { return(addToCache); } // Set Kill range CurrentCacheObject.KillRange = SetKillRange(); if (CurrentCacheObject.RadiusDistance <= CurrentCacheObject.KillRange) { AnyMobsInRange = true; } return(addToCache); }
private static bool RefreshItemStats(GItemBaseType tempbasetype) { bool isNewLogItem = false; c_ItemMd5Hash = HashGenerator.GenerateItemHash(CurrentCacheObject.Position, CurrentCacheObject.ActorSNO, CurrentCacheObject.InternalName, CurrentWorldDynamicId, c_ItemQuality, c_ItemLevel); if (!GenericCache.ContainsKey(c_ItemMd5Hash)) { GenericCache.AddToCache(new GenericCacheObject(c_ItemMd5Hash, null, new TimeSpan(1, 0, 0))); try { isNewLogItem = true; if (tempbasetype == GItemBaseType.Armor || tempbasetype == GItemBaseType.WeaponOneHand || tempbasetype == GItemBaseType.WeaponTwoHand || tempbasetype == GItemBaseType.WeaponRange || tempbasetype == GItemBaseType.Jewelry || tempbasetype == GItemBaseType.FollowerItem || tempbasetype == GItemBaseType.Offhand) { try { int iThisQuality; ItemsDroppedStats.Total++; if (c_ItemQuality >= ItemQuality.Legendary) { iThisQuality = QUALITYORANGE; } else if (c_ItemQuality >= ItemQuality.Rare4) { iThisQuality = QUALITYYELLOW; } else if (c_ItemQuality >= ItemQuality.Magic1) { iThisQuality = QUALITYBLUE; } else { iThisQuality = QUALITYWHITE; } ItemsDroppedStats.TotalPerQuality[iThisQuality]++; ItemsDroppedStats.TotalPerLevel[c_ItemLevel]++; ItemsDroppedStats.TotalPerQPerL[iThisQuality, c_ItemLevel]++; } catch (Exception ex) { Logger.LogError("Error Refreshing Item Stats for Equippable Item: " + ex.ToString()); } } else if (tempbasetype == GItemBaseType.Gem) { try { int iThisGemType = 0; ItemsDroppedStats.TotalGems++; if (c_item_GItemType == GItemType.Topaz) { iThisGemType = GEMTOPAZ; } if (c_item_GItemType == GItemType.Ruby) { iThisGemType = GEMRUBY; } if (c_item_GItemType == GItemType.Emerald) { iThisGemType = GEMEMERALD; } if (c_item_GItemType == GItemType.Amethyst) { iThisGemType = GEMAMETHYST; } if (c_item_GItemType == GItemType.Diamond) { iThisGemType = GEMDIAMOND; } ItemsDroppedStats.GemsPerType[iThisGemType]++; ItemsDroppedStats.GemsPerLevel[c_ItemLevel]++; ItemsDroppedStats.GemsPerTPerL[iThisGemType, c_ItemLevel]++; } catch (Exception ex) { Logger.LogError("Error refreshing item stats for Gem: " + ex.ToString()); } } else if (c_item_GItemType == GItemType.InfernalKey) { try { ItemsDroppedStats.TotalInfernalKeys++; } catch (Exception ex) { Logger.LogError("Error refreshing item stats for InfernalKey: " + ex.ToString()); } } // See if we should update the stats file if (DateTime.UtcNow.Subtract(ItemStatsLastPostedReport).TotalSeconds > 10) { try { ItemStatsLastPostedReport = DateTime.UtcNow; OutputReport(); } catch (Exception ex) { Logger.LogError("Error Calling OutputReport from RefreshItemStats " + ex.ToString()); } } } catch (Exception ex) { Logger.LogError("Couldn't do Item Stats" + ex.ToString()); } } return(isNewLogItem); }
/// <summary> /// Called when DemonBuddy shut down. /// </summary> public void OnShutdown() { GenericCache.Shutdown(); GenericBlacklist.Shutdown(); Helpers.PluginCheck.Shutdown(); }
/// <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); } }
/// <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); } }