Beispiel #1
0
        /// <summary>
        /// This coroutine interacts with the waypoint and waits for the world panel to open. When called from a hideout,
        /// the waypoint must be in spawn range, otherwise the coroutine will fail. The movement is done without returning,
        /// so this should be carefully used when not in town.
        /// </summary>
        /// <returns>An OpenStashError that describes the result.</returns>
        public static async Task <Results.OpenWaypointError> OpenWaypoint()
        {
            await Coroutines.CloseBlockingWindows();

            await Coroutines.FinishCurrentAction();

            var waypoint = LokiPoe.ObjectManager.Waypoint;

            if (waypoint == null)
            {
                if (!LokiPoe.Me.IsInTown)
                {
                    return(Results.OpenWaypointError.NoWaypoint);
                }

                if (
                    !await
                    Navigation.MoveToLocation(ExilePather.FastWalkablePositionFor(Actor.GuessWaypointLocation()), 25,
                                              60000, () => LokiPoe.ObjectManager.Waypoint != null))
                {
                    return(Results.OpenWaypointError.CouldNotMoveToWaypoint);
                }

                waypoint = LokiPoe.ObjectManager.Waypoint;
                if (waypoint == null)
                {
                    return(Results.OpenWaypointError.NoWaypoint);
                }
            }

            if (ExilePather.PathDistance(LokiPoe.MyPosition, waypoint.Position) > 30)
            {
                if (!await Navigation.MoveToLocation(ExilePather.FastWalkablePositionFor(waypoint.Position), 25, 15000, () => false))
                {
                    return(Results.OpenWaypointError.CouldNotMoveToWaypoint);
                }
            }

            await Coroutines.FinishCurrentAction();

            waypoint = LokiPoe.ObjectManager.Waypoint;
            if (waypoint == null)
            {
                return(Results.OpenWaypointError.NoWaypoint);
            }

            if (!await InteractWith(waypoint))
            {
                return(Results.OpenWaypointError.InteractFailed);
            }

            if (!await WaitForWorldPanel())
            {
                return(Results.OpenWaypointError.WorldPanelDidNotOpen);
            }

            await Coroutine.Sleep(1000); // Adding this in to let the gui load more

            return(Results.OpenWaypointError.None);
        }
Beispiel #2
0
        /// <summary>
        /// Used to reset the starting area transition. This is for handling local area transitions.
        /// </summary>
        public void ResetStartingAreaTransition()
        {
            var at = LokiPoe.ObjectManager.GetObjectsByType <AreaTransition>().OrderBy(a => a.Distance).FirstOrDefault();

            StartingAreaTransitionName     = at != null ? at.Name : "";
            StartingAreaTransitionLocation = at != null
                ? ExilePather.FastWalkablePositionFor(at)
                : Vector2i.Zero;
        }
Beispiel #3
0
        public BreachCache(Breach breach)
        {
            Id               = breach.Id;
            Position         = breach.Position;
            WalkablePosition = ExilePather.FastWalkablePositionFor(breach);
            IsValid          = true;

            Log.InfoFormat("[BreachCache] {0} {1}", Id, WalkablePosition);
        }
        public MonolithCache(Monolith monolith)
        {
            Id               = monolith.Id;
            Position         = monolith.Position;
            WalkablePosition = ExilePather.FastWalkablePositionFor(monolith);
            MonsterName      = monolith.Name;
            MonsterMetadata  = monolith.MonsterTypeMetadata;
            Essences         = monolith.EssenceBaseItemTypes;
            IsValid          = true;

            Log.InfoFormat("[MonolithCache] {0} {1} {2} {3} {4}", Id, WalkablePosition, MonsterName, MonsterMetadata,
                           string.Join(", ", Essences.Select(e => e.Metadata)));
        }
Beispiel #5
0
        private AreaStateCache(uint hash)
        {
            Hash = hash;

            WorldArea = LokiPoe.CurrentWorldArea;

            ShouldCheckForWaypoint = LokiPoe.CurrentWorldArea.HasWaypoint;

            ShouldCheckForStash = LokiPoe.CurrentWorldArea.IsTown;
            HasStashLocation    = false;

            HasWaypointLocation = false;

            var areaId = WorldArea.Id;

            HasWaypointEntry = LokiPoe.InstanceInfo.AvailableWaypoints.ContainsKey(areaId);

            SeenAreaTransitions = new List <string>();

            //GenerateStaticLocations();

            ResetStartingAreaTransition();

            var portal = LokiPoe.ObjectManager.GetObjectsByType <Portal>().OrderBy(a => a.Distance).FirstOrDefault();

            StartingPortalLocation = portal != null
                ? ExilePather.FastWalkablePositionFor(portal)
                : Vector2i.Zero;

            //if (!DisableDefaultExplorer)
            //{
            //    var ge = new GridExplorer
            //    {
            //        AutoResetOnAreaChange = false
            //    };
            //    Explorer = ge;
            //}
        }
Beispiel #6
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();
                }
            }
        }
Beispiel #7
0
        public static WorldPosition FindWalkablePosition(Vector2i pos, int radius = 15)
        {
            var walkable = ExilePather.FastWalkablePositionFor(pos, radius);

            return(ExilePather.PathExistsBetween(LokiPoe.MyPosition, walkable) ? new WorldPosition(walkable) : null);
        }
Beispiel #8
0
        /// <summary>
        /// This coroutine interacts with stash and waits for the stash panel to open. When called from a hideout,
        /// the stash must be in spawn range, otherwise the coroutine will fail.
        /// </summary>
        ///<param name="guild">Should the guild stash be opened?</param>
        /// <returns>An OpenStashError that describes the result.</returns>
        public static async Task <Results.OpenStashError> OpenStash(bool guild = false)
        {
            await Coroutines.CloseBlockingWindows();

            await Coroutines.FinishCurrentAction();

            var stash = Stash.DetermineStash(guild);

            if (stash == null)
            {
                if (LokiPoe.Me.IsInHideout)
                {
                    return(Results.OpenStashError.NoStash);
                }

                var mtl = await Navigation.MoveToLocation(
                    ExilePather.FastWalkablePositionFor(Actor.GuessStashLocation()), 25, 60000,
                    () => Stash.DetermineStash(guild) != null && Stash.DetermineStash(guild).Distance < 75);

                if (!mtl)
                {
                    return(Results.OpenStashError.CouldNotMoveToStash);
                }

                stash = Stash.DetermineStash(guild);
                if (stash == null)
                {
                    return(Results.OpenStashError.NoStash);
                }
            }

            if (stash.Distance > 30)
            {
                var p = stash.Position;
                if (!await Navigation.MoveToLocation(ExilePather.FastWalkablePositionFor(p), 25, 15000, () => false))
                {
                    return(Results.OpenStashError.CouldNotMoveToStash);
                }
            }

            await Coroutines.FinishCurrentAction();

            stash = Stash.DetermineStash(guild);
            if (stash == null)
            {
                return(Results.OpenStashError.NoStash);
            }

            if (!await InteractWith(stash))
            {
                return(Results.OpenStashError.InteractFailed);
            }

            if (guild)
            {
                if (!await Dialog.WaitForPanel(Dialog.PanelType.GuildStash))
                {
                    return(Results.OpenStashError.StashPanelDidNotOpen);
                }

                await Stash.WaitForStashTabChange(guild : true);
            }
            else
            {
                if (!await Dialog.WaitForPanel(Dialog.PanelType.Stash))
                {
                    return(Results.OpenStashError.StashPanelDidNotOpen);
                }

                await Stash.WaitForStashTabChange();
            }

            return(Results.OpenStashError.None);
        }
Beispiel #9
0
        /// <summary>
        /// This coroutine will attempt to take a portal
        /// </summary>
        /// <returns>true if the portal was taken, and an area change occurred, and false otherwise.</returns>
        public static async Task <bool> TakeClosestPortal()
        {
            var sw = Stopwatch.StartNew();

            if (LokiPoe.ConfigManager.IsAlwaysHighlightEnabled)
            {
                CommunityLib.Log.InfoFormat("[TakeClosestPortal] Now disabling Always Highlight to avoid label issues.");
                LokiPoe.Input.SimulateKeyEvent(LokiPoe.Input.Binding.highlight_toggle, true, false, false);
                await Coroutine.Sleep(16);
            }

            NetworkObject portal = null;

            while (portal == null || !portal.IsTargetable)
            {
                CommunityLib.Log.DebugFormat($"[TakeClosestPortal] Now waiting for the portal to spawn. {sw.Elapsed} elapsed.");
                await Coroutines.LatencyWait();

                portal =
                    LokiPoe.ObjectManager.GetObjectsByType <Portal>()
                    .Where(p => p.Distance < 50)
                    .OrderBy(p => p.Distance)
                    .FirstOrDefault();

                if (sw.ElapsedMilliseconds > 10000)
                {
                    break;
                }
            }

            if (portal == null)
            {
                CommunityLib.Log.ErrorFormat("[TakeClosestPortal] A portal was not found.");
                return(false);
            }

            var pos = ExilePather.FastWalkablePositionFor(portal);

            CommunityLib.Log.Debug($"[TakeClosestPortal] The portal was found at {pos}.");

            if (!await Navigation.MoveToLocation(pos, 5, 10000, () => false))
            {
                return(false);
            }

            var hash = LokiPoe.LocalData.AreaHash;

            // Try to interact 3 times.
            for (var i = 0; i < 3; i++)
            {
                if (LokiPoe.Me.IsDead)
                {
                    break;
                }

                await Coroutines.FinishCurrentAction();

                CommunityLib.Log.Debug($"[TakeClosestPortal] The portal to interact with is {portal.Id} at {pos}.");

                if (await InteractWith(portal))
                {
                    if (await Areas.WaitForAreaChange(hash))
                    {
                        CommunityLib.Log.Debug("[TakeClosestPortal] The portal has been taken.");
                        return(true);
                    }
                }

                await Coroutine.Sleep(1000);
            }

            CommunityLib.Log.ErrorFormat("[TakeClosestPortal] We have failed to take the portal 3 times.");
            return(false);
        }
Beispiel #10
0
        /// <summary>
        /// This coroutine interacts with a npc and waits for the npc dialog panel to open. When called for a non-main town npc
        /// the npc must be in spawn range, otherwise the coroutine will fail. The movement is done without returning,
        /// so this should be carefully used when not in town.
        /// </summary>
        /// <param name="name">Name of the NPC to interact with</param>
        /// <param name="skipTalk">Should the bot skip all the dialog NPC's have before the dialog panel appears"</param>
        /// <returns>An OpenStashError that describes the result.</returns>
        public static async Task <Results.TalkToNpcError> TalkToNpc(string name, bool skipTalk = true)
        {
            await Coroutines.CloseBlockingWindows();

            await Coroutines.FinishCurrentAction();

            var npc = LokiPoe.ObjectManager.GetObjectByName(name);

            if (npc == null)
            {
                var pos = Actor.GuessNpcLocation(name);

                if (pos == Vector2i.Zero)
                {
                    return(Results.TalkToNpcError.NoNpc);
                }

                if (!await Navigation.MoveToLocation(ExilePather.FastWalkablePositionFor(pos), 25, 60000, () => LokiPoe.ObjectManager.GetObjectByName(name) != null))
                {
                    return(Results.TalkToNpcError.CouldNotMoveToNpc);
                }

                npc = LokiPoe.ObjectManager.GetObjectByName(name);
                if (npc == null)
                {
                    return(Results.TalkToNpcError.NoNpc);
                }
            }

            if (ExilePather.PathDistance(LokiPoe.MyPosition, npc.Position) > 30)
            {
                if (!await Navigation.MoveToLocation(ExilePather.FastWalkablePositionFor(npc.Position), 25, 15000, () => false))
                {
                    return(Results.TalkToNpcError.CouldNotMoveToNpc);
                }

                npc = LokiPoe.ObjectManager.GetObjectByName(name);
                if (npc == null)
                {
                    return(Results.TalkToNpcError.NoNpc);
                }
            }

            await Coroutines.FinishCurrentAction();

            if (!await InteractWith(npc))
            {
                return(Results.TalkToNpcError.InteractFailed);
            }

            // Clicking continue if NPC is blablaing (xD)
            while (skipTalk && LokiPoe.InGameState.NpcDialogUi.DialogDepth != 1)
            {
                if (LokiPoe.InGameState.NpcDialogUi.DialogDepth == 2)
                {
                    CommunityLib.Log.DebugFormat("[CommunityLib][TalkToNpc] Now closing a dialog/reward window.");
                    LokiPoe.Input.SimulateKeyEvent(Keys.Escape, true, false, false);
                    // Give the client enough time to close the gui itself. It waits for the server to show the new one.
                    await Coroutine.Sleep(LokiPoe.Random.Next(800, 1000));

                    await Coroutines.ReactionWait();
                }
                else
                {
                    CommunityLib.Log.InfoFormat("[CommunityLib][TalkToNpc] Waiting for the Npc window to open.");
                    await Coroutines.ReactionWait();
                }
            }

            if (!await Dialog.WaitForPanel(Dialog.PanelType.NpcDialog))
            {
                return(Results.TalkToNpcError.NpcDialogPanelDidNotOpen);
            }

            return(Results.TalkToNpcError.None);
        }