예제 #1
0
        private static void Update()
        {
            try
            {
                using (new PerformanceLogger("CacheUI Update"))
                {
                    if (_isUpdating)
                    {
                        return;
                    }

                    if (_dataModel.IsDefaultVisible && DateTime.UtcNow.Subtract(_lastUpdatedDefault).TotalMilliseconds > 250)
                    {
                        _isUpdating         = true;
                        _dataModel.Cache    = new ObservableCollection <CacheUIObject>(GetCacheActorList());
                        _lastUpdatedDefault = DateTime.UtcNow;
                    }

                    if (_dataModel.IsLazyCacheVisible && DateTime.UtcNow.Subtract(_lastUpdatedLazy).TotalMilliseconds > 50)
                    {
                        _isUpdating      = true;
                        _lastUpdatedLazy = DateTime.UtcNow;
                    }

                    _isUpdating = false;
                }
            }
            catch (Exception ex)
            {
                _isUpdating = false;
                Logger.LogError("Error in CacheUI Worker: " + ex);
            }
        }
예제 #2
0
            protected static Composite CreateUnstuckBehavior()
            {
                return(new Decorator(ret => !IsDone,

                                     new Action(ret =>
                {
                    try
                    {
                        if (!_points.Any() || IsWithinRange(_points.First()))
                        {
                            Logger.Log(TrinityLogLevel.Debug, LogCategory.Movement, "Arrived at Destination {0} Distance={1}", _points.First().ToString(), _points.First());

                            IsDone = true;
                            return RunStatus.Failure;
                        }

                        if (ZetaDia.Me.Movement.IsMoving)
                        {
                            _lastMoving = DateTime.UtcNow;
                        }

                        // Ooooh bad bad bad - always use Navigator raycast!
                        //var rayResult = ZetaDia.Physics.Raycast(ZetaDia.Me.Position, _points.First(), NavCellFlags.AllowWalk);
                        var raycastHit = Navigator.Raycast(ZetaDia.Me.Position, _points.First());
                        var stuckResult = DateTime.UtcNow.Subtract(_lastMoving).TotalMilliseconds > 250;

                        if (stuckResult || raycastHit)
                        {
                            Logger.Log(TrinityLogLevel.Debug, LogCategory.Movement, "Discarded Location {0} Distance={1} RaycastResult={2} StuckResult={3} LocationsRemaining={4}", _points.First().ToString(), _points.First().Distance(ZetaDia.Me.Position), raycastHit, stuckResult, _points.Count - 1);
                            _points.RemoveAt(0);
                        }

                        if (_points.Any() && _points.First() != Vector3.Zero && ZetaDia.Me.Movement.MoveActor(_points.First()) == 1)
                        {
                            return RunStatus.Success;
                        }

                        IsDone = true;
                        return RunStatus.Failure;
                    }
                    catch (Exception ex)
                    {
                        Logger.LogError("Exception in UnstuckBehavior: " + ex);
                        return RunStatus.Failure;
                    }
                })
                                     ));
            }
예제 #3
0
        private static bool CacheDiaObject(DiaObject freshObject)
        {
            if (!freshObject.IsValid)
            {
                return(false);
            }

            /*
             *  Initialize Variables
             */
            bool AddToCache;

            RefreshStepInit(out AddToCache);

            /*
             *  Get primary reference objects and keys
             */
            c_diaObject = freshObject;

            // Ractor GUID
            CurrentCacheObject.RActorGuid = freshObject.RActorGuid;
            // Check to see if we've already looked at this GUID
            CurrentCacheObject.RActorGuid = freshObject.RActorGuid;
            CurrentCacheObject.ACDGuid    = freshObject.ACDGuid;

            // Get Name
            CurrentCacheObject.InternalName = nameNumberTrimRegex.Replace(freshObject.Name, "");
            CurrentCacheObject.InternalName = nameNumberTrimRegex.Replace(freshObject.Name, "");

            CurrentCacheObject.ActorSNO  = freshObject.ActorSNO;
            CurrentCacheObject.ActorType = freshObject.ActorType;
            CurrentCacheObject.ACDGuid   = freshObject.ACDGuid;
            if (CurrentCacheObject.CommonData == null)
            {
                c_IgnoreReason = "ACDNull";
                return(false);
            }
            if (!CurrentCacheObject.CommonData.IsValid)
            {
                c_IgnoreReason = "ACDInvalid";
            }

            // Position
            CurrentCacheObject.Position = CurrentCacheObject.Object.Position;

            // Distance
            CurrentCacheObject.Distance = Player.Position.Distance2D(CurrentCacheObject.Position);

            float radius;

            if (!DataDictionary.CustomObjectRadius.TryGetValue(CurrentCacheObject.ActorSNO, out radius))
            {
                try
                {
                    radius = CurrentCacheObject.Object.CollisionSphere.Radius;
                }
                catch (Exception ex)
                {
                    Logger.LogError(LogCategory.CacheManagement, "Error refreshing Radius: {0}", ex.Message);
                }
            }

            // Radius Distance
            CurrentCacheObject.Radius = radius;

            // Have ActorSNO Check for SNO based navigation obstacle hashlist
            c_IsObstacle = DataDictionary.NavigationObstacleIds.Contains(CurrentCacheObject.ActorSNO);

            // Add Cell Weight for Obstacle
            if (c_IsObstacle)
            {
                Vector3 pos;
                if (!CacheData.Position.TryGetValue(CurrentCacheObject.RActorGuid, out pos))
                {
                    CurrentCacheObject.Position = c_diaObject.Position;
                    //CacheData.Position.Add(CurrentCacheObject.RActorGuid, CurrentCacheObject.Position);
                }
                if (pos != Vector3.Zero)
                {
                    CurrentCacheObject.Position = pos;
                }

                CacheData.NavigationObstacles.Add(new CacheObstacleObject()
                {
                    ActorSNO   = CurrentCacheObject.ActorSNO,
                    Name       = CurrentCacheObject.InternalName,
                    Position   = CurrentCacheObject.Position,
                    Radius     = CurrentCacheObject.Radius,
                    ObjectType = CurrentCacheObject.Type,
                });

                ((MainGridProvider)MainGridProvider).AddCellWeightingObstacle(CurrentCacheObject.ActorSNO, CurrentCacheObject.Radius);

                c_IgnoreReason = "NavigationObstacle";
                AddToCache     = false;
                return(AddToCache);
            }

            // Summons by the player
            AddToCache = RefreshStepCachedSummons(AddToCache);
            if (!AddToCache)
            {
                c_IgnoreReason = "CachedPlayerSummons"; return(AddToCache);
            }

            using (new PerformanceLogger("RefreshDiaObject.CachedType"))
            {
                /*
                 * Set Object Type
                 */
                AddToCache = RefreshStepCachedObjectType(AddToCache);
                if (!AddToCache)
                {
                    c_IgnoreReason = "CachedObjectType"; return(AddToCache);
                }
            }

            CurrentCacheObject.Type = CurrentCacheObject.Type;
            if (CurrentCacheObject.Type != GObjectType.Item)
            {
                CurrentCacheObject.ObjectHash = HashGenerator.GenerateWorldObjectHash(CurrentCacheObject.ActorSNO, CurrentCacheObject.Position, CurrentCacheObject.Type.ToString(), Trinity.CurrentWorldDynamicId);
            }

            // Check Blacklists
            AddToCache = RefreshStepCheckBlacklists(AddToCache);
            if (!AddToCache)
            {
                c_IgnoreReason = "CheckBlacklists"; return(AddToCache);
            }

            if (CurrentCacheObject.Type == GObjectType.Item)
            {
                if (GenericBlacklist.ContainsKey(CurrentCacheObject.ObjectHash))
                {
                    AddToCache     = false;
                    c_IgnoreReason = "GenericBlacklist";
                    return(AddToCache);
                }
            }

            // Always Refresh ZDiff for every object
            AddToCache = RefreshStepObjectTypeZDiff(AddToCache);
            if (!AddToCache)
            {
                c_IgnoreReason = "ZDiff"; return(AddToCache);
            }

            using (new PerformanceLogger("RefreshDiaObject.MainObjectType"))
            {
                /*
                 * Main Switch on Object Type - Refresh individual object types (Units, Items, Gizmos)
                 */
                RefreshStepMainObjectType(ref AddToCache);
                if (!AddToCache)
                {
                    c_IgnoreReason = "MainObjectType"; return(AddToCache);
                }
            }

            if (CurrentCacheObject.ObjectHash != String.Empty && GenericBlacklist.ContainsKey(CurrentCacheObject.ObjectHash))
            {
                AddToCache      = false;
                c_IgnoreSubStep = "GenericBlacklist";
                return(AddToCache);
            }

            // Ignore anything unknown
            AddToCache = RefreshStepIgnoreUnknown(AddToCache);
            if (!AddToCache)
            {
                c_IgnoreReason = "IgnoreUnknown"; return(AddToCache);
            }

            using (new PerformanceLogger("RefreshDiaObject.LoS"))
            {
                // Ignore all LoS
                AddToCache = RefreshStepIgnoreLoS(AddToCache);
                if (!AddToCache)
                {
                    c_IgnoreReason = "IgnoreLoS"; return(AddToCache);
                }
            }

            // If it's a unit, add it to the monster cache
            AddUnitToMonsterObstacleCache();

            c_IgnoreReason = "None";

            CurrentCacheObject.ACDGuid            = CurrentCacheObject.ACDGuid;
            CurrentCacheObject.ActorSNO           = CurrentCacheObject.ActorSNO;
            CurrentCacheObject.Animation          = c_CurrentAnimation;
            CurrentCacheObject.DBItemBaseType     = c_DBItemBaseType;
            CurrentCacheObject.DBItemType         = c_DBItemType;
            CurrentCacheObject.DirectionVector    = c_DirectionVector;
            CurrentCacheObject.Distance           = CurrentCacheObject.Distance;
            CurrentCacheObject.DynamicID          = CurrentCacheObject.DynamicID;
            CurrentCacheObject.FollowerType       = c_item_tFollowerType;
            CurrentCacheObject.GameBalanceID      = CurrentCacheObject.GameBalanceID;
            CurrentCacheObject.GoldAmount         = c_GoldStackSize;
            CurrentCacheObject.HasAffixShielded   = c_unit_HasShieldAffix;
            CurrentCacheObject.HasBeenInLoS       = c_HasBeenInLoS;
            CurrentCacheObject.HasBeenNavigable   = c_HasBeenNavigable;
            CurrentCacheObject.HasBeenRaycastable = c_HasBeenRaycastable;
            CurrentCacheObject.HasDotDPS          = c_HasDotDPS;
            CurrentCacheObject.HitPoints          = c_HitPoints;
            CurrentCacheObject.HitPointsPct       = c_HitPointsPct;
            CurrentCacheObject.InternalName       = CurrentCacheObject.InternalName;
            CurrentCacheObject.IsAttackable       = c_unit_IsAttackable;
            CurrentCacheObject.IsElite            = c_unit_IsElite;
            CurrentCacheObject.IsEliteRareUnique  = c_IsEliteRareUnique;
            CurrentCacheObject.IsFacingPlayer     = c_IsFacingPlayer;
            CurrentCacheObject.IsMinion           = c_unit_IsMinion;
            CurrentCacheObject.IsRare             = c_unit_IsRare;
            CurrentCacheObject.IsTreasureGoblin   = c_unit_IsTreasureGoblin;
            CurrentCacheObject.IsUnique           = c_unit_IsUnique;
            CurrentCacheObject.ItemLevel          = c_ItemLevel;
            CurrentCacheObject.ItemLink           = c_ItemLink;
            CurrentCacheObject.ItemQuality        = c_ItemQuality;
            CurrentCacheObject.MonsterAffixes     = c_MonsterAffixes;
            CurrentCacheObject.MonsterSize        = c_unit_MonsterSize;
            CurrentCacheObject.OneHanded          = c_IsOneHandedItem;
            CurrentCacheObject.RActorGuid         = CurrentCacheObject.RActorGuid;
            CurrentCacheObject.Radius             = CurrentCacheObject.Radius;
            CurrentCacheObject.Rotation           = c_Rotation;
            CurrentCacheObject.TrinityItemType    = c_item_GItemType;
            CurrentCacheObject.TwoHanded          = c_IsTwoHandedItem;
            CurrentCacheObject.Type = CurrentCacheObject.Type;
            ObjectCache.Add(CurrentCacheObject);
            return(true);
        }
예제 #4
0
        /// <summary>
        /// This is wired up by Plugin.OnEnabled, and called when the bot is started
        /// </summary>
        /// <param name="bot"></param>
        private static void TrinityBotStart(IBot bot)
        {
            Logger.Log("Bot Starting");
            DateTime timeBotStart = DateTime.UtcNow;

            V.ValidateLoad();

            // Recording of all the XML's in use this run
            try
            {
                string sThisProfile = GlobalSettings.Instance.LastProfile;
                if (sThisProfile != CurrentProfile)
                {
                    ProfileHistory.Add(sThisProfile);
                    CurrentProfile = sThisProfile;
                    if (FirstProfile == "")
                    {
                        FirstProfile = sThisProfile;
                    }
                }

                DebugUtil.LogSystemInformation();
            }
            catch
            {
            }

            if (!ItemDropStats.MaintainStatTracking)
            {
                ItemDropStats.ItemStatsWhenStartedBot   = DateTime.UtcNow;
                ItemDropStats.ItemStatsLastPostedReport = DateTime.UtcNow;
                ItemDropStats.MaintainStatTracking      = true;
            }
            else
            {
                Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation,
                           "Note: Maintaining item stats from previous run. To reset stats fully, please restart DB.");
            }

            TrinityItemManager.ResetBackPackCheck();

            BeginInvoke(UsedProfileManager.RefreshProfileBlacklists);
            UsedProfileManager.SetProfileInWindowTitle();

            BotManager.ReplaceTreeHooks();
            TreeHooks.Instance.OnHooksCleared += BotManager.InstanceOnOnHooksCleared;


            PlayerMover.TimeLastRecordedPosition = DateTime.UtcNow;
            PlayerMover.LastRestartedGame        = DateTime.UtcNow;
            Logger.Log("Bot Starting, Resetting Gold Inactivity Timer");
            GoldInactivity.Instance.ResetCheckGold();
            XpInactivity.Instance.ResetCheckXp();

            if (CharacterSettings.Instance.KillRadius < 20)
            {
                Logger.Log("WARNING: Low Kill Radius detected, currently set to: {0} (you can change this through Demonbuddy bot settings)",
                           CharacterSettings.Instance.KillRadius);
            }

            if (CharacterSettings.Instance.LootRadius < 50)
            {
                Logger.Log("WARNING: Low Gold Loot Radius detected, currently set to: {0} (you can change this through Demonbuddy bot settings)",
                           CharacterSettings.Instance.LootRadius);
            }

            if (Settings.Loot.ItemFilterMode == ItemFilterMode.TrinityWithItemRules)
            {
                try
                {
                    if (StashRule == null)
                    {
                        StashRule = new Interpreter();
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogError("Error configuring ItemRules Interpreter: " + ex);
                }
            }

            Logger.LogDebug("Trinity BotStart took {0:0}ms", DateTime.UtcNow.Subtract(timeBotStart).TotalMilliseconds);
        }
예제 #5
0
        /// <summary>
        /// TownRunCheckOverlord - determine if we should do a town-run or not
        /// </summary>
        /// <param name="ret"></param>
        /// <returns></returns>
        internal static bool TownRunCanRun(object ret)
        {
            try
            {
                using (new PerformanceLogger("TownRunOverlord"))
                {
                    if (ZetaDia.Me == null || !ZetaDia.Me.IsValid)
                    {
                        return(false);
                    }

                    Trinity.IsReadyToTownRun = false;

                    if (Trinity.Player.IsDead)
                    {
                        return(false);
                    }

                    var a5hubMaxRangePoint = new Vector3(441.0972f, 519.0328f, 7.718145f);
                    var a5waypoint         = new Vector3(556.9158f, 524.3738f, 2.796464f);
                    var a5hubRange         = a5waypoint.Distance2D(a5hubMaxRangePoint);
                    if (Trinity.Player.LevelAreaId == 270011 && Trinity.Player.Position.Distance2D(a5waypoint) >= a5hubRange)
                    {
                        return(false);
                    }

                    // Check if we should be forcing a town-run
                    if (!Trinity.Player.IsInTown && Trinity.ForceVendorRunASAP || BrainBehavior.IsVendoring)
                    {
                        if (!LastTownRunCheckResult)
                        {
                            if (BrainBehavior.IsVendoring)
                            {
                                Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation, "Looks like we are being asked to force a town-run by a profile/plugin/new DB feature, now doing so.");
                            }
                        }
                        SetPreTownRunPosition();
                        Trinity.IsReadyToTownRun = true;
                    }

                    // Time safety switch for more advanced town-run checking to prevent CPU spam
                    if (DateTime.UtcNow.Subtract(LastCheckBackpackDurability).TotalSeconds > 6)
                    {
                        LastCheckBackpackDurability = DateTime.UtcNow;

                        // Check for no space in backpack
                        Vector2 validLocation = TrinityItemManager.FindValidBackpackLocation(true);
                        if (validLocation.X < 0 || validLocation.Y < 0)
                        {
                            Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation, "No more space to pickup a 2-slot item, now running town-run routine. (TownRun)");
                            if (!LastTownRunCheckResult)
                            {
                                LastTownRunCheckResult = true;
                            }
                            Trinity.IsReadyToTownRun = true;

                            Trinity.ForceVendorRunASAP = true;
                            // Record the first position when we run out of bag space, so we can return later
                            SetPreTownRunPosition();
                        }

                        if (ZetaDia.Me.IsValid)
                        {
                            var equippedItems = ZetaDia.Me.Inventory.Equipped.Where(i => i.DurabilityCurrent != i.DurabilityMax).ToList();
                            if (equippedItems.Any())
                            {
                                double min = equippedItems.Min(i => i.DurabilityPercent);

                                float threshold   = Trinity.Player.IsInTown ? 0.50f : Zeta.Bot.Settings.CharacterSettings.Instance.RepairWhenDurabilityBelow;
                                bool  needsRepair = min <= threshold;

                                if (needsRepair)
                                {
                                    Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation, "Items may need repair, now running town-run routine.");

                                    Trinity.IsReadyToTownRun   = true;
                                    Trinity.ForceVendorRunASAP = true;
                                    SetPreTownRunPosition();
                                }
                            }
                        }
                    }

                    if (ErrorDialog.IsVisible)
                    {
                        Trinity.IsReadyToTownRun = false;
                    }

                    LastTownRunCheckResult = Trinity.IsReadyToTownRun;

                    // Clear blacklists to triple check any potential targets
                    if (Trinity.IsReadyToTownRun)
                    {
                        Trinity.Blacklist3Seconds  = new HashSet <int>();
                        Trinity.Blacklist15Seconds = new HashSet <int>();
                        Trinity.Blacklist60Seconds = new HashSet <int>();
                        Trinity.Blacklist90Seconds = new HashSet <int>();
                    }

                    // Fix for A1 new game with bags full
                    if (Trinity.Player.LevelAreaId == 19947 && ZetaDia.CurrentQuest.QuestSNO == 87700 && (ZetaDia.CurrentQuest.StepId == -1 || ZetaDia.CurrentQuest.StepId == 42))
                    {
                        Logger.Log(TrinityLogLevel.Verbose, LogCategory.UserInformation, "Can't townrun with the current quest!");
                        Trinity.IsReadyToTownRun = false;
                    }

                    if (Trinity.IsReadyToTownRun && !(BrainBehavior.IsVendoring || Trinity.Player.IsInTown))
                    {
                        string cantUseTPreason;
                        if (!ZetaDia.Me.CanUseTownPortal(out cantUseTPreason) && !ZetaDia.IsInTown)
                        {
                            Logger.Log(TrinityLogLevel.Verbose, LogCategory.UserInformation, "It appears we need to town run but can't: {0}", cantUseTPreason);
                            Trinity.IsReadyToTownRun = false;
                        }
                    }


                    if (Trinity.IsReadyToTownRun && DataDictionary.BossLevelAreaIDs.Contains(Trinity.Player.LevelAreaId))
                    {
                        Logger.Log(TrinityLogLevel.Debug, LogCategory.GlobalHandler, "Unable to Town Portal - Boss Area!");
                        return(false);
                    }
                    if (Trinity.IsReadyToTownRun && ZetaDia.IsInTown && DbProvider.DeathHandler.EquipmentNeedsEmergencyRepair())
                    {
                        Logger.Log(TrinityLogLevel.Debug, LogCategory.GlobalHandler, "EquipmentNeedsEmergencyRepair!");
                        return(true);
                    }
                    if (Trinity.IsReadyToTownRun && Trinity.CurrentTarget != null)
                    {
                        TownRunCheckTimer.Restart();
                        Logger.Log(TrinityLogLevel.Debug, LogCategory.GlobalHandler, "Restarting TownRunCheckTimer, we have a target!");
                        return(false);
                    }

                    if (Trinity.IsReadyToTownRun && DataDictionary.NeverTownPortalLevelAreaIds.Contains(Trinity.Player.LevelAreaId))
                    {
                        Logger.Log(TrinityLogLevel.Debug, LogCategory.GlobalHandler, "Unable to Town Portal in this area!");
                        return(false);
                    }
                    if (Trinity.IsReadyToTownRun && (TownRunTimerFinished() || BrainBehavior.IsVendoring))
                    {
                        //Logger.Log(TrinityLogLevel.Verbose, LogCategory.UserInformation, "Town run timer finished {0} or in town {1} or is vendoring {2} (TownRun)",
                        //    TownRunTimerFinished(), Trinity.Player.IsInTown, BrainBehavior.IsVendoring);
                        Trinity.IsReadyToTownRun = false;
                        return(true);
                    }
                    if (Trinity.IsReadyToTownRun && !TownRunCheckTimer.IsRunning)
                    {
                        Logger.Log(TrinityLogLevel.Verbose, LogCategory.UserInformation, "Starting town run timer");
                        TownRunCheckTimer.Start();
                        _loggedAnythingThisStash = false;
                        _loggedJunkThisStash     = false;
                    }
                    return(false);
                }
            }
            catch (Exception ex)
            {
                Logger.LogError("Error Getting TownRun {0}", ex.Message);
                return(false);
            }
        }
예제 #6
0
        /// <summary>
        /// Called when user Enable the plugin.
        /// </summary>
        public void OnEnabled()
        {
            try
            {
                Logger.Log("OnEnable start");
                DateTime dateOnEnabledStart = DateTime.UtcNow;

                BotMain.OnStart += TrinityBotStart;
                BotMain.OnStop  += TrinityBotStop;

                SetWindowTitle();
                TabUi.InstallTab();

                if (!Directory.Exists(FileManager.PluginPath))
                {
                    Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation, "Fatal Error - cannot enable plugin. Invalid path: {0}", FileManager.PluginPath);
                    Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation, "Please check you have installed the plugin to the correct location, and then restart DemonBuddy and re-enable the plugin.");
                    Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation, @"Plugin should be installed to \<DemonBuddyFolder>\Plugins\Trinity\");
                }
                else
                {
                    _isPluginEnabled = true;

                    PluginCheck.Start();

                    // Settings are available after this...
                    LoadConfiguration();

                    Navigator.PlayerMover = new PlayerMover();
                    BotManager.SetUnstuckProvider();
                    GameEvents.OnPlayerDied   += TrinityOnDeath;
                    GameEvents.OnGameJoined   += TrinityOnJoinGame;
                    GameEvents.OnGameLeft     += TrinityOnLeaveGame;
                    GameEvents.OnItemSold     += ItemEvents.TrinityOnItemSold;
                    GameEvents.OnItemSalvaged += ItemEvents.TrinityOnItemSalvaged;
                    GameEvents.OnItemDropped  += ItemEvents.TrinityOnItemDropped;
                    GameEvents.OnItemStashed  += ItemEvents.TrinityOnItemStashed;
                    GameEvents.OnItemIdentificationRequest += ItemEvents.TrinityOnOnItemIdentificationRequest;
                    GameEvents.OnGameChanged  += GameEvents_OnGameChanged;
                    GameEvents.OnWorldChanged += GameEvents_OnWorldChanged;

                    CombatTargeting.Instance.Provider   = new BlankCombatProvider();
                    LootTargeting.Instance.Provider     = new BlankLootProvider();
                    ObstacleTargeting.Instance.Provider = new BlankObstacleProvider();

                    if (Settings.Loot.ItemFilterMode != ItemFilterMode.DemonBuddy)
                    {
                        ItemManager.Current = new TrinityItemManager();
                    }

                    // Safety check incase DB "OnStart" event didn't fire properly
                    if (BotMain.IsRunning)
                    {
                        TrinityBotStart(null);
                        if (ZetaDia.IsInGame)
                        {
                            TrinityOnJoinGame(null, null);
                        }
                    }

                    BotManager.SetBotTicksPerSecond();

                    UILoader.PreLoadWindowContent();

                    Events.OnCacheUpdated += Enemies.Update;

                    Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation, "ENABLED: {0} now in action!", Description);
                }

                if (StashRule != null)
                {
                    // reseting stash rules
                    BeginInvoke(() => StashRule.reset());
                }

                Logger.LogDebug("OnEnable took {0}ms", DateTime.UtcNow.Subtract(dateOnEnabledStart).TotalMilliseconds);
            }
            catch (Exception ex)
            {
                Logger.LogError("Error in OnEnable: " + ex);
            }
        }
예제 #7
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);
            }
        }