Esempio n. 1
0
        private void TimerCallback(object sender, EventArgs e)
        {
            // Make sure everything is loaded first.
            if (!LokiPoe.IsBotFullyLoaded)
            {
                return;
            }

            if (!IsEnabledFunc())
            {
                return;
            }

            LokiPoe.BeginDispatchIfNecessary(Dispatcher, () =>
            {
                var data = GetDataFunc();
                if (data.IsValid)
                {
                    foreach (var renderGroup in _renderGroups)
                    {
                        renderGroup.Render(data);
                    }
                    data.IsValid = false;
                }

                _renderNavGrid.Enabled        = ShowNavGrid.IsChecked == true;
                _renderLocalPlayer.Enabled    = ShowLocalPlayer.IsChecked == true;
                _renderLocalPlayer.LockCamera = LockCameraToPlayer.IsChecked == true;
                _renderMesh.Enabled           = ShowNavMesh.IsChecked == true;
            });
        }
Esempio n. 2
0
        private void CreateNavMeshOverlay()
        {
            var vertices = new List <Point3D>();
            var indices  = new List <int>();

            NavMesh navMesh = ExilePather.PolyPathfinder.NavMesh;

            int tcount = navMesh.GetMaxTiles();

            for (int i = 0; i < tcount; i++)
            {
                MeshTile tile = navMesh.GetTile(i);
                if (tile.Header == null)
                {
                    continue;
                }

                AddMeshTile(tile, vertices, indices);
            }

            var b = new MeshBuilder();

            for (int i = 0; i < indices.Count - 3; i += 3)
            {
                b.AddTriangle(vertices[indices[i + 2]], vertices[indices[i + 1]], vertices[indices[i]]);
            }

            _initialSeed = _curData.Seed;

            LokiPoe.BeginDispatchIfNecessary(View.Dispatcher, () =>
                                             (Visual as MeshVisual3D).Content =
                                                 new GeometryModel3D(b.ToMesh(true), MaterialHelper.CreateMaterial(Colors.DeepSkyBlue, 0.35)));
        }
Esempio n. 3
0
 private void LokiPoeOnOnGuiTick(object sender, GuiTickEventArgs guiTickEventArgs)
 {
     if (!BotManager.IsRunning)
     {
         using (LokiPoe.AcquireFrame())
         {
             _data.Update();
         }
     }
 }
Esempio n. 4
0
        private void TreeViewObjects_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs <object> e)
        {
            using (LokiPoe.AcquireFrame())
            {
                using (LokiPoe.Memory.TemporaryCacheState(false))
                {
                    TextBoxInfoRaw.Text = "";

                    var item = TreeViewObjects.SelectedItem as TreeViewItem;

                    if (item == null || item.Tag == null)
                    {
                        return;
                    }

                    var obj = item.Tag as NetworkObject;
                    if (obj != null)
                    {
                        if (obj.IsValid && LokiPoe.ObjectManager.GetObjectByAddress(obj.BaseAddress) != null)
                        {
                            ShowObjectInformation(obj);
                        }
                        return;
                    }

                    var skill = item.Tag as Skill;
                    if (skill != null)
                    {
                        ShowSkillInformation(skill);
                        return;
                    }

                    var itm = item.Tag as Item;
                    if (itm != null)
                    {
                        ShowItemInformation(itm);
                        return;
                    }

                    var area = item.Tag as DatWorldAreaWrapper;
                    if (area != null)
                    {
                        ShowAreaInformation(area);
                        return;
                    }

                    var quest = item.Tag as DatQuestWrapper;
                    if (quest != null)
                    {
                        ShowQuestInformation(quest);
                        return;
                    }
                }
            }
        }
Esempio n. 5
0
 private void ReloadExilePatherButton_OnClick(object sender, RoutedEventArgs e)
 {
     Dispatcher.BeginInvoke(new Action(() =>
     {
         using (LokiPoe.AcquireFrame())
         {
             ExilePather.Reload(true);
         }
         GetDataFunc().ForceReload = true;
         Log.InfoFormat("[ReloadExilePatherButton_OnClick] Done!");
     }));
 }
Esempio n. 6
0
 private void SetCharNameButton_Click(object sender, RoutedEventArgs e)
 {
     using (LokiPoe.AcquireFrame())
     {
         if (LokiPoe.IsInGame)
         {
             var charName = LokiPoe.Me.Name;
             Settings.Instance.Character = string.IsNullOrEmpty(charName) ? "error" : charName;
         }
         else
         {
             MessageBoxes.Error("You must be in the game.");
         }
     }
 }
Esempio n. 7
0
        /// <summary>
        /// This function will add a location that we can reference later. An example of a location
        /// would be area transitions or NPCs which can despawn.
        /// </summary>
        public void AddLocation(Vector2i position, int id, string name)
        {
            var location = new Location
            {
                Position = position,
                Id       = id,
                Name     = name
            };

            _locations.Add(location);

            Log.DebugFormat("Adding location [\"{0}\"][{1}] = {2} for area [0x{3:X}]", location.Name,
                            location.Id, location.Position, Hash);

            LokiPoe.InvokeEvent(OnLocationAdded, null, new OnLocationAddedEventArgs(location));
        }
Esempio n. 8
0
        /// <summary> The plugin tick callback. Do any update logic here. </summary>
        public void Tick()
        {
            // Don't update while we are not in the game.
            if (!LokiPoe.IsInGame)
            {
                return;
            }

            // Update the current skillgems once per major event.
            if (!_ranOnce)
            {
                // This can trigger gui code from a non-gui thread, so we need to run it on a gui thread.
                LokiPoe.BeginDispatchIfNecessary(new Action(() => GemLevelerSettings.Instance.RefreshSkillGemsList()));
                _ranOnce = true;
                return;
            }
        }
Esempio n. 9
0
        internal void ExecutePythonButton_Click(object sender, RoutedEventArgs e)
        {
            PythonExampleSettings.Instance.Code = PyInputTextBox.Text;
            Dispatcher.BeginInvoke(new Action(() =>
            {
                lock (_pythonExample)
                {
                    _pythonExample.InitializeScriptManager();

                    using (LokiPoe.AcquireFrame())
                    {
                        // For total control, GetStatement logic is this:
                        var scope        = _pythonExample.ScriptManager.Scope;
                        var scriptSource =
                            _pythonExample.ScriptManager.Engine.CreateScriptSourceFromString(PythonExampleSettings.Instance.Code);
                        scope.SetVariable("ioproxy", _pythonExample.ScriptManager.IoProxy);
                        scriptSource.Execute(scope);
                        scope.GetVariable <Action>("Execute")();
                    }
                }
            }));
        }
Esempio n. 10
0
        private void CreateVisual()
        {
            _initialSeed = _curData.Seed;

            if (_curData.IsInGame)
            {
                var builder = new MeshBuilder(true, false);

                List <Tripper.Tools.Math.Vector3> verts;
                List <int> indices;

                if (!RDPathfinder.UseNewGetTris)
                {
                    RDPathfinder.GetTris(_curData.CachedTerrainData, 2, out verts, out indices);                     // 2 is the walkable value used for pathfinding
                }
                else
                {
                    RDPathfinder.GetTris2(_curData.CachedTerrainData, 2, out verts, out indices, out var rects);                     // 2 is the walkaloe value used for pathfinding
                }

                for (int i = 0; i < indices.Count - 3; i += 3)
                {
                    var p0 = verts[indices[i + 2]];
                    var p1 = verts[indices[i + 1]];
                    var p2 = verts[indices[i + 0]];

                    // We need to swap Y/Z for display purposes.
                    builder.AddTriangle(new Point3D(p0.X, p0.Z, p0.Y), new Point3D(p1.X, p1.Z, p1.Y), new Point3D(p2.X, p2.Z, p2.Y));
                }

                LokiPoe.BeginDispatchIfNecessary(View.Dispatcher,
                                                 () => (Visual as MeshVisual3D).Content = new GeometryModel3D(builder.ToMesh(true), Materials.White));
            }
            else
            {
                LokiPoe.BeginDispatchIfNecessary(View.Dispatcher, () => (Visual as MeshVisual3D).Content = null);
            }
        }
Esempio n. 11
0
		private void LoadCharactersButton_OnClick(object sender, RoutedEventArgs e)
		{
			CharactersComboBox.Items.Clear();

			var chars = new List<string>();
			using (LokiPoe.AcquireFrame())
			{
				if (LokiPoe.StateManager.IsSelectCharacterStateActive && !LokiPoe.StateManager.IsCreateCharacterStateActive)
				{
					if (LokiPoe.SelectCharacterState.IsCharacterListLoaded)
					{
						foreach (var ch in LokiPoe.SelectCharacterState.Characters.OrderBy(ce => ce.Name))
						{
							chars.Add(ch.Name);
						}
					}
				}
			}

			foreach (var @char in chars)
			{
				CharactersComboBox.Items.Add(@char);
			}

			if (!string.IsNullOrEmpty(AutoLoginSettings.Instance.Character))
			{
				var name = AutoLoginSettings.Instance.Character;
				for (int i = 0; i < CharactersComboBox.Items.Count; i++)
				{
					if (((string) (CharactersComboBox.Items[i])).Equals(name))
					{
						CharactersComboBox.SelectedIndex = i;
						break;
					}
				}
			}
		}
Esempio n. 12
0
        private void OnTick()
        {
            //if (Explorer != null)
            //{
            //    Explorer.Tick();
            //}

            var update = false;

            if (!_itemThrottle.IsRunning)
            {
                _itemThrottle.Start();
                update = true;
            }
            else
            {
                if (_itemThrottle.ElapsedMilliseconds >= ItemThrottleMs)
                {
                    update = true;
                }
            }

            //using (new PerformanceTimer("Tick::WorldItem", 1))
            {
                if (update)
                {
                    var myPos = LokiPoe.MyPosition;

                    var added = 0;
                    foreach (var worldItem in LokiPoe.ObjectManager.GetObjectsByType <WorldItem>())
                    {
                        var doAdd = false;

                        Vector2i pos;
                        if (!_ignoreItems.TryGetValue(worldItem.Id, out pos))
                        {
                            doAdd = true;
                        }
                        else
                        {
                            if (pos != worldItem.Position)
                            {
                                Log.InfoFormat("[AreaStateCache] An item collision has been detected! Item id {0}.", worldItem.Id);
                                _ignoreItems.Remove(worldItem.Id);
                                doAdd = true;
                            }
                        }

                        if (doAdd)
                        {
                            if (added > 10)
                            {
                                break;
                            }

                            ++added;

                            var item = worldItem.Item;

                            if (worldItem.IsAllocatedToOther)
                            {
                                if (DateTime.Now < worldItem.PublicTime)
                                {
                                    //Log.InfoFormat("[AreaStateCache] The item {0} is not being marked for pickup because it is allocated to another player.", item.FullName);
                                    //_ignoreItems.Add(worldItem.Id, worldItem.Position);
                                    continue;
                                }
                            }

                            var visibleOverride = false;
                            if (LootVisibleItemsOverride)
                            {
                                // We can only consider items when they are visible, otherwise we ignore stuff we might want.
                                if (!LokiPoe.ConfigManager.IsAlwaysHighlightEnabled)
                                {
                                    continue;
                                }

                                if (LokiPoe.Input.GetClickableHighlightLabelPosition(worldItem) != Vector2.Zero)
                                {
                                    visibleOverride = true;
                                }
                            }

                            IItemFilter filter = null;
                            if (visibleOverride || ItemEvaluator.Match(item, EvaluationType.PickUp, out filter))
                            {
                                var location = new ItemLocation
                                {
                                    Id       = worldItem.Id,
                                    Name     = worldItem.Name,
                                    Position = worldItem.Position,
                                    Rarity   = worldItem.Item.Rarity,
                                    Metadata = worldItem.Item.Metadata
                                };

                                if (_itemLocations.ContainsKey(location.Id))
                                {
                                    _itemLocations[location.Id] = location;
                                }
                                else
                                {
                                    _itemLocations.Add(location.Id, location);
                                }

                                Log.InfoFormat("[AreaStateCache] The location {0} [{1}] is being added from filter [{3}].{2}", location.Id,
                                               location.Name,
                                               worldItem.HasAllocation ? " [Allocation " + worldItem.PublicTime + "]" : "",
                                               filter != null ? filter.Name : "(null)");
                            }

                            _ignoreItems.Add(worldItem.Id, worldItem.Position);
                        }
                    }

                    var toRemove = new List <int>();
                    foreach (var kvp in _itemLocations)
                    {
                        if (Blacklist.Contains(kvp.Key))
                        {
                            Log.InfoFormat("[AreaStateCache] The location {0} [{1}] is being removed because the id has been Blacklisted.",
                                           kvp.Value.Id, kvp.Value.Name);
                            toRemove.Add(kvp.Value.Id);
                        }
                        else if (myPos.Distance(kvp.Value.Position) < 30)
                        {
                            if (LokiPoe.ObjectManager.GetObjectById <WorldItem>(kvp.Value.Id) == null)
                            {
                                Log.InfoFormat("[AreaStateCache] The location {0} [{1}] is being removed because the WorldItem does not exist.",
                                               kvp.Value.Id, kvp.Value.Name);
                                toRemove.Add(kvp.Value.Id);
                            }
                        }
                    }

                    foreach (var id in toRemove)
                    {
                        _itemLocations.Remove(id);
                    }

                    _itemThrottle.Restart();
                }
            }

            if (!_chestThrottle.IsRunning)
            {
                _chestThrottle.Start();
            }
            else
            {
                if (_chestThrottle.ElapsedMilliseconds >= ChestThrottleMs)
                {
                    //using (new PerformanceTimer("Tick::Chest", 1))
                    {
                        var addedChests = new List <ChestLocation>();
                        foreach (var chest in LokiPoe.ObjectManager.GetObjectsByType <Chest>().ToList())
                        {
                            ChestLocation location;
                            if (!_chestLocations.TryGetValue(chest.Id, out location))
                            {
                                location = new ChestLocation
                                {
                                    Id            = chest.Id,
                                    Name          = chest.Name,
                                    IsTargetable  = chest.IsTargetable,
                                    IsOpened      = chest.IsOpened,
                                    IsStrongBox   = chest.IsStrongBox,
                                    IsVaalVessel  = chest.IsVaalVessel,
                                    OpensOnDamage = chest.OpensOnDamage,
                                    Position      = chest.Position,
                                    Stats         = chest.Stats.ToList(),
                                    IsIdentified  = chest.IsIdentified,
                                    IsBreakable   = chest.OpensOnDamage,
                                    Rarity        = chest.Rarity,
                                    Metadata      = chest.Type
                                };

                                _chestLocations.Add(location.Id, location);

                                addedChests.Add(location);
                            }

                            if (!location.IsOpened)
                            {
                                location.IsOpened     = chest.IsOpened;
                                location.IsLocked     = chest.IsLocked;
                                location.IsTargetable = chest.IsTargetable;
                                // Support for chests that change locked state, without the lock state updating.
                                var tc = chest.Components.TransitionableComponent;
                                if (tc != null)
                                {
                                    if ((tc.Flag1 & 2) != 0)
                                    {
                                        location.IsLocked = false;
                                    }
                                }
                                if (chest.IsVaalVessel)
                                {
                                    location.IsLocked = false;
                                }
                                if (!location.IsCorrupted && chest.IsCorrupted)
                                {
                                    location.IsCorrupted = chest.IsCorrupted;
                                    location.Stats       = chest.Stats.ToList();
                                }
                                if (!location.IsIdentified && chest.IsIdentified)
                                {
                                    location.IsIdentified = chest.IsIdentified;
                                    location.Stats        = chest.Stats.ToList();
                                }
                            }

                            if (addedChests.Count > 10)
                            {
                                break;
                            }
                        }

                        foreach (var location in addedChests)
                        {
                            if (!location.IsBreakable)
                            {
                                location.Position = ExilePather.FastWalkablePositionFor(location.Position);
                            }

                            LokiPoe.InvokeEvent(OnChestLocationAdded, null, new OnChestLocationAddedEventArgs(location));
                        }

                        addedChests.Clear();

                        _chestThrottle.Restart();
                    }
                }
            }

            if (!_questThrottle.IsRunning)
            {
                _questThrottle.Start();
            }
            else
            {
                if (_questThrottle.ElapsedMilliseconds >= QuestThrottleMs)
                {
                    if (LokiPoe.CurrentWorldArea.IsMissionArea)
                    {
                        if (!HasKaruiSpiritLocation)
                        {
                            var obj = LokiPoe.ObjectManager.GetObjectByName("Karui Spirit");
                            if (obj != null)
                            {
                                AddLocation(ExilePather.FastWalkablePositionFor(obj), obj.Id, obj.Name);
                                HasKaruiSpiritLocation = true;
                            }
                        }
                    }

                    _questThrottle.Restart();
                }
            }

            if (!_throttle.IsRunning)
            {
                _throttle.Start();
            }
            else
            {
                if (_throttle.ElapsedMilliseconds >= ThrottleMs)
                {
                    if (!_timeInInstance.IsRunning)
                    {
                        _timeInInstance.Start();
                    }

                    if (!_timeInArea.IsRunning)
                    {
                        _timeInArea.Start();
                    }

                    // Do we need to update wp state flags.
                    if (_updateCheckForWaypoint)
                    {
                        // If the current area doesn't have a wp, we do not want to do any more logic processing.
                        if (!LokiPoe.CurrentWorldArea.HasWaypoint)
                        {
                            _updateCheckForWaypoint = false;
                            ShouldCheckForWaypoint  = false;
                            HasWaypointLocation     = false;
                            HasWaypointEntry        = false;
                        }
                        else
                        {
                            ShouldCheckForWaypoint = true;
                        }
                    }

                    // Do we need to update at state flags.
                    if (_updateAreaTransition)
                    {
                        ShouldCheckForAreaTransition = true;
                    }

                    if (ShouldCheckForStash)
                    {
                        //using (new PerformanceTimer("ShouldCheckForStash", 1))
                        {
                            if (!HasStashLocation)
                            {
                                var stash = LokiPoe.ObjectManager.Stash;
                                if (stash != null)
                                {
                                    // Save the location so we know where it is when the entity isn't in view.
                                    AddLocation(ExilePather.FastWalkablePositionFor(stash), stash.Id, "Stash");

                                    // We now have the waypoint location.
                                    HasStashLocation = true;
                                }
                            }
                            else
                            {
                                ShouldCheckForStash = false;
                            }
                        }
                    }

                    // If we need to handle wps.
                    if (ShouldCheckForWaypoint)
                    {
                        //using (new PerformanceTimer("ShouldCheckForWaypoint", 1))
                        {
                            // If we don't have the wp location yet, check to see if we see one.
                            if (!HasWaypointLocation)
                            {
                                var wp = LokiPoe.ObjectManager.Waypoint;
                                if (wp != null)
                                {
                                    // Save the location so we know where it is when the entity isn't in view.
                                    AddLocation(ExilePather.FastWalkablePositionFor(wp), wp.Id, "Waypoint");

                                    // We now have the waypoint location.
                                    HasWaypointLocation = true;
                                }
                            }

                            // If we don't have the wp entry yet, poll for us having it now.
                            // But only if we've seen the waypoint, since otherwise there's no way we have it.
                            if (HasWaypointLocation && !HasWaypointEntry)
                            {
                                var areaId = WorldArea.Id;
                                HasWaypointEntry = LokiPoe.InstanceInfo.AvailableWaypoints.ContainsKey(areaId);
                            }

                            // Once we have both the location and the entry, we do not need to execute wp logic anymore.
                            if (HasWaypointLocation && HasWaypointEntry)
                            {
                                _updateCheckForWaypoint = false;
                                ShouldCheckForWaypoint  = false;
                            }
                        }
                    }

                    // If we need to handle ats.
                    if (ShouldCheckForAreaTransition)
                    {
                        //using (new PerformanceTimer("ShouldCheckForAreaTransition", 1))
                        {
                            // If there are any area transitions on screen, add them if we don't already know of them.
                            foreach (var transition in LokiPoe.ObjectManager.Objects.OfType <AreaTransition>().ToList())
                            {
                                var name = transition.Name;

                                // We have to check all this in order to handle the areas that have transitions with the same name, but different
                                // entity ids.
                                if (HasLocation(name, transition.Id))
                                {
                                    continue;
                                }

                                AddLocation(ExilePather.FastWalkablePositionFor(transition), transition.Id, name);

                                if (!SeenAreaTransitions.Contains(name))
                                {
                                    SeenAreaTransitions.Add(name);
                                }
                            }
                        }
                    }

                    // Check to see if we need a new anchor point to kite back towards.
                    if (!_hasAnchorPoint || LokiPoe.LocalData.AreaHash != _anchorPointSeed)
                    {
                        ResetAnchorPoint();
                        ResetCurrentAnchorPoint();
                    }

                    _throttle.Restart();
                }
            }
        }
Esempio n. 13
0
        /// <summary>
        /// Goes to the specified area using waypoint.
        /// </summary>
        /// <param name="name">Name of the area eg "Highgate"</param>
        /// <param name="difficulty"></param>
        /// <param name="newInstance">Do you want to open new instance?</param>
        /// <returns></returns>
        public static async Task <LokiPoe.InGameState.TakeWaypointResult> TakeWaypoint(string name, Difficulty difficulty = Difficulty.Unknown, bool newInstance = false)
        {
            //We are already there
            if (LokiPoe.LocalData.WorldArea.Name == name && LokiPoe.LocalData.WorldArea.Difficulty == difficulty && !newInstance)
            {
                return(LokiPoe.InGameState.TakeWaypointResult.None);
            }

            //await Coroutines.CloseBlockingWindows();

            // First try of fastgotohideout instead of LokiPoe.InGameState.WorldUi.GoToHideout()
            if (name.Equals("Hideout", StringComparison.OrdinalIgnoreCase) && (LokiPoe.Me.IsInHideout || LokiPoe.Me.IsInTown))
            {
                await Coroutines.CloseBlockingWindows();

                var res = await FastGoToHideout();

                switch (res)
                {
                case Results.FastGoToHideoutResult.None:
                    return(LokiPoe.InGameState.TakeWaypointResult.None);

                case Results.FastGoToHideoutResult.NoHideout:
                    return(LokiPoe.InGameState.TakeWaypointResult.AreaNotFound);

                case Results.FastGoToHideoutResult.NotInGame:
                    return(LokiPoe.InGameState.TakeWaypointResult.UiNotOpen);
                    //if we timed out then try to use default method like below
                }
            }

            if (!LokiPoe.InGameState.WorldUi.IsOpened)
            {
                var opened = await LibCoroutines.OpenWaypoint();

                if (opened != Results.OpenWaypointError.None)
                {
                    CommunityLib.Log.ErrorFormat("[TakeWaypoint] Fail to open waypoint. Error: \"{0}\".", opened);
                    return(LokiPoe.InGameState.TakeWaypointResult.WaypointControlNotVisible);
                }
            }
            if (difficulty == Difficulty.Unknown)
            {
                difficulty = LokiPoe.CurrentWorldArea.Difficulty;
            }

            //var areaId = name == "Hideout" ? "" : GetZoneId(difficulty.ToString(), name);
            CommunityLib.Log.InfoFormat($"[TakeWaypoint] Going to {name} at {difficulty}.");

            var areaHash = LokiPoe.LocalData.AreaHash;
            var taken    = name.Equals("Hideout", StringComparison.OrdinalIgnoreCase)
                ? LokiPoe.InGameState.WorldUi.GoToHideout()
                : LokiPoe.InGameState.WorldUi.TakeWaypoint(LokiPoe.GetZoneId(difficulty.ToString(), name), newInstance, Int32.MaxValue);

            if (taken != LokiPoe.InGameState.TakeWaypointResult.None)
            {
                CommunityLib.Log.ErrorFormat("[TakeWaypoint] Failed to take waypoint to \"{0}\". Error: \"{1}\".", name, taken);
                return(taken);
            }

            var awaited = await Areas.WaitForAreaChange(areaHash);

            return(awaited ? LokiPoe.InGameState.TakeWaypointResult.None : LokiPoe.InGameState.TakeWaypointResult.CouldNotJoinNewInstance);
        }
Esempio n. 14
0
        private void ButtonRefresh_OnClick(object sender, RoutedEventArgs e)
        {
            TreeViewObjects.Items.Clear();

            using (LokiPoe.AcquireFrame())
            {
                using (LokiPoe.Memory.TemporaryCacheState(false))
                {
                    if (!LokiPoe.IsInGame)
                    {
                        return;
                    }

                    var objs = LokiPoe.ObjectManager.Objects.OrderBy(o => o.Distance).ToList();

                    var used = new Dictionary <int, bool>();

                    var serverEffects = objs.OfType <ServerEffect>().ToList();
                    foreach (var entry in serverEffects)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var effects = objs.OfType <Effect>().ToList();
                    foreach (var entry in effects)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var monoliths = objs.OfType <Monolith>().Where(m => !m.IsMini).ToList();
                    foreach (var entry in monoliths)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var miniMonoliths = objs.OfType <MiniMonolith>().ToList();
                    foreach (var entry in miniMonoliths)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var breaches = objs.OfType <Breach>().ToList();
                    foreach (var entry in breaches)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var abyss1 = objs.OfType <AbyssStartNode>().ToList();
                    foreach (var entry in abyss1)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var abyss2 = objs.OfType <AbyssNodeMini>().ToList();
                    foreach (var entry in abyss2)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var abyss3 = objs.OfType <AbyssNodeSmall>().ToList();
                    foreach (var entry in abyss3)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var abyss4 = objs.OfType <AbyssFinalNodeChest>().ToList();
                    foreach (var entry in abyss4)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var abyss5 = objs.OfType <AbyssCrackSpawner>().ToList();
                    foreach (var entry in abyss5)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var abyss6 = objs.OfType <AbyssFinalNodeSubArea>().ToList();
                    foreach (var entry in abyss6)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var abyss7 = objs.OfType <AbyssNodeLarge>().ToList();
                    foreach (var entry in abyss7)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var shrines = objs.OfType <Shrine>().ToList();
                    foreach (var entry in shrines)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var darkShrines = objs.OfType <DarkShrine>().ToList();
                    foreach (var entry in darkShrines)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var stoneAltars = objs.OfType <StoneAltar>().ToList();
                    foreach (var entry in stoneAltars)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var players = objs.OfType <Player>().ToList();
                    foreach (var entry in players)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var monsters = objs.OfType <Monster>().ToList();
                    foreach (var entry in monsters)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var npcs = objs.OfType <Npc>().ToList();
                    foreach (var entry in npcs)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var worldItems = objs.OfType <WorldItem>().ToList();
                    foreach (var entry in worldItems)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var portals = objs.OfType <Portal>().ToList();
                    foreach (var entry in portals)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var chests = objs.OfType <Chest>().ToList();
                    foreach (var entry in chests)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var areaTransitions = objs.OfType <AreaTransition>().ToList();
                    foreach (var entry in areaTransitions)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var doors = LokiPoe.ObjectManager.Doors.OrderBy(o => o.Distance).ToList();
                    foreach (var entry in doors)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var triggerableBlockages = objs.OfType <TriggerableBlockage>().Where(o =>
                                                                                         !doors.Contains(o) && !abyss3.Contains(o) && !abyss4.Contains(o) && !abyss6.Contains(o) && !abyss7.Contains(o))
                                               .ToList();
                    foreach (var entry in triggerableBlockages)
                    {
                        if (!used.ContainsKey(entry.Id))
                        {
                            used.Add(entry.Id, true);
                        }
                    }

                    var others = objs.Where(o => !used.ContainsKey(o.Id)).ToList();

                    var skills = LokiPoe.ObjectManager.Me.AvailableSkills.ToList();

                    var abyss = new List <NetworkObject>();
                    abyss.AddRange(abyss1);
                    abyss.AddRange(abyss2);
                    abyss.AddRange(abyss3);
                    abyss.AddRange(abyss4);
                    abyss.AddRange(abyss6);
                    abyss.AddRange(abyss7);
                    abyss = abyss.OrderBy(n => n.DistanceSqr).ToList();

                    // Find a list of types...
                    TreeViewObjects.Items.Add(FillTreeNode(new List <DatWorldAreaWrapper>
                    {
                        LokiPoe.CurrentWorldArea
                    }, "Current Area"));
                    TreeViewObjects.Items.Add("");

                    var header = new TreeViewItem
                    {
                        Header = "Current Player"
                    };

                    var header2 = new TreeViewItem
                    {
                        Header = "Inventories"
                    };
                    header2.Items.Add(FillTreeNode(LokiPoe.Me.EquippedItems, "Equipped Items"));
                    header2.Items.Add(FillTreeNode(LokiPoe.InstanceInfo.GetPlayerInventoryItemsBySlot(InventorySlot.Flasks), "Equipped Flasks"));
                    header2.Items.Add(FillTreeNode(LokiPoe.InstanceInfo.GetPlayerInventoryItemsBySlot(InventorySlot.Main), "Inventory Items"));
                    header.Items.Add(header2);
                    header.Items.Add(FillTreeNode(Dat.Quests, "Quests"));
                    header.Items.Add(FillTreeNode(skills, "Skills"));
                    TreeViewObjects.Items.Add(header);

                    TreeViewObjects.Items.Add("");

                    TreeViewObjects.Items.Add(FillTreeNode(areaTransitions, "Area Transitions"));
                    TreeViewObjects.Items.Add(FillTreeNode(chests, "Chests"));
                    TreeViewObjects.Items.Add(FillTreeNode(worldItems, "Items [Ground]"));
                    TreeViewObjects.Items.Add(FillTreeNode(monsters, "Monsters"));
                    TreeViewObjects.Items.Add(FillTreeNode(npcs, "NPCs"));
                    TreeViewObjects.Items.Add(FillTreeNode(players, "Players"));

                    TreeViewObjects.Items.Add("");
                    header = new TreeViewItem
                    {
                        Header = "Abyss"
                    };
                    header.Items.Add(FillTreeNode(abyss, "Nodes"));
                    header.Items.Add(FillTreeNode(abyss5, "Spawners"));
                    TreeViewObjects.Items.Add(header);

                    TreeViewObjects.Items.Add(FillTreeNode(breaches, "Breaches"));
                    TreeViewObjects.Items.Add(FillTreeNode(darkShrines, "Dark Shrines"));
                    TreeViewObjects.Items.Add(FillTreeNode(doors, "Doors"));
                    TreeViewObjects.Items.Add(FillTreeNode(effects, "Effects"));
                    TreeViewObjects.Items.Add(FillTreeNode(miniMonoliths, "MiniMonoliths"));
                    TreeViewObjects.Items.Add(FillTreeNode(monoliths, "Monoliths"));
                    TreeViewObjects.Items.Add(FillTreeNode(portals, "Portals"));
                    TreeViewObjects.Items.Add(FillTreeNode(serverEffects, "ServerEffects"));
                    TreeViewObjects.Items.Add(FillTreeNode(shrines, "Shrines"));
                    TreeViewObjects.Items.Add(FillTreeNode(stoneAltars, "Stone Altars"));
                    TreeViewObjects.Items.Add(FillTreeNode(triggerableBlockages, "Triggerable Blockages"));

                    TreeViewObjects.Items.Add("");

                    TreeViewObjects.Items.Add(FillTreeNode(others, "<Uncategorized>"));
                }
            }
        }
        /// <summary>
        /// Attempts to move towards a position. This function will perform pathfinding logic and take into consideration move distance
        /// to try and smoothly move towards a point.
        /// </summary>
        /// <param name="position">The position to move towards.</param>
        /// <param name="user">A user object passed.</param>
        /// <returns>true if the position was moved towards, and false if there was a pathfinding error.</returns>
        public bool MoveTowards(Vector2i position, params dynamic[] user)
        {
            _coroutinePosition = position;
            _coroutineUser     = user;

            if (_coroutine == null || _coroutine.IsFinished)
            {
                _coroutine = new Coroutine(() => MainCoroutine());
            }

            // Variant 1: If you do not want all execution to be blocked inside MoveTowards, and instead let
            // other logic run between MoveTowards calls when you need to yield execution, then you would simply
            // only call Resume once per MoveTowards call, and coroutine execution would continue where it left off.
            // However, this might result in unexpected side-effects since it's a new design, so use with care...

            /*
             * try
             * {
             *      _coroutine.Resume();
             * }
             * catch
             * {
             *      var c = _coroutine;
             *      _coroutine = null;
             *      c.Dispose();
             *      throw;
             * }
             */

            // Variant 2: If you want all execution to be blocked inside MoveTowards, as it is
            // with the normal player mover, then you would want to loop until the coroutine is finished,
            // and release the frame at the end of the loop. The main coroutine would be re-created after
            // it finishes each time.
            while (!_coroutine.IsFinished)
            {
                try
                {
                    _coroutine.Resume();
                }
                catch
                {
                    // This block of code gets copied around, but isn't explained. The reason why this is done
                    // this way, is in the event Dispose throws an exception, the coroutine object ('_coroutine') would not
                    // get set to null, and execution would be locked up with an invalid coroutine object. By keeping it in
                    // a local first, then clearing the class variable, if an exception happens in Dispose, we can
                    // recover because '_coroutine' was set to null and will be created again next Tick.
                    var c = _coroutine;
                    _coroutine = null;
                    c.Dispose();
                    throw;
                }

                if (!_coroutine.IsFinished)
                {
                    // Just like normal player mover, we release the frame after logic is done running, to trigger
                    // the next frame for execution to continue. Execution control stays within this loop though.
                    LokiPoe.ReleaseFrameProfiler("OldCoroutinePlayerMover.MoveTowards", () =>
                    {
                        // How you Sleep is up to the mover and what is actually needed, but here's one example
                        // of what you can do (allows changing the sleep inside the coroutine to affect here)/
                        Thread.Sleep(_coroutineSleepValue);
                    });
                }
            }

            // If the coroutine finished, return what it returned.
            if (_coroutine.IsFinished)
            {
                return((bool)_coroutine.Result);
            }

            // Otherwise, the coroutine is still running, so we're going to return true
            // since the move is in progress (if it wasn't the coroutine would have returned false,
            // and we'd not reach here.)
            return(true);
        }