示例#1
0
        /// <summary>
        /// This coroutine waits for an area transition to be usable.
        /// </summary>
        /// <param name="name">The name of the area transition.</param>
        /// <param name="timeout">How long to wait before the coroutine fails.</param>
        /// <returns>true on succes and false on failure.</returns>
        public static async Task <bool> WaitForAreaTransition(string name, int timeout = 3000)
        {
            CommunityLib.Log.DebugFormat("[WaitForAreaTransition]");

            var sw = Stopwatch.StartNew();

            while (true)
            {
                var at = LokiPoe.ObjectManager.GetObjectByName <AreaTransition>(name);
                if (at != null)
                {
                    if (at.IsTargetable)
                    {
                        break;
                    }
                }

                if (sw.ElapsedMilliseconds > timeout)
                {
                    CommunityLib.Log.ErrorFormat("[WaitForAreaTransition] Timeout.");
                    return(false);
                }

                CommunityLib.Log.DebugFormat(
                    "[WaitForAreaTransition] We have been waiting {0} for the area transition {1} to be usable.",
                    sw.Elapsed, name);

                await Coroutines.LatencyWait();
            }

            return(true);
        }
示例#2
0
        /// <summary>
        /// Waits for a stash tab to change. Pass -1 to lastId to wait for the initial tab.
        /// </summary>
        /// <param name="lastId">The last InventoryId before changing tabs.</param>
        /// <param name="timeout">The timeout of the function.</param>
        /// <param name="guild">Whether it's the guild stash or not</param>
        /// <returns>true if the tab was changed and false otherwise.</returns>
        public static async Task <bool> WaitForStashTabChange(int lastId = -1, int timeout = 10000, bool guild = false)
        {
            var sw     = Stopwatch.StartNew();
            var invTab = guild ? GuildStashUI.StashTabInfo : StashUI.StashTabInfo;

            while (invTab == null || invTab.InventoryId == lastId)
            {
                await Coroutine.Sleep(1);

                if (guild)
                {
                    if (!GuildStashUI.IsOpened)
                    {
                        return(false);
                    }
                    else
                    if (!StashUI.IsOpened)
                    {
                        return(false);
                    }
                }

                invTab = guild ? GuildStashUI.StashTabInfo : StashUI.StashTabInfo;
                if (sw.ElapsedMilliseconds > timeout)
                {
                    return(false);
                }
            }

            await Coroutines.LatencyWait((float)MathEx.Random(.5d, 2d));

            //await Coroutines.ReactionWait();
            return(true);
        }
示例#3
0
        /// <summary>
        /// This task (awaitable) handles the whole process to talk to a NPC to reach the list of choices
        /// </summary>
        /// <param name="npcName">Name of the NPC to interact with</param>
        /// <returns>boolean</returns>
        public static async Task<bool> TalkToNpc(string npcName)
        {
            //await Coroutines.CloseBlockingWindows();
            var ret = await LibCoroutines.TalkToNpc(npcName, true);

            await Coroutines.LatencyWait();
            await Coroutines.ReactionWait();

            return ret == Results.TalkToNpcError.None;
        }
示例#4
0
        /// <summary>
        /// Overload for UpdateItemsInStash, taking a list of tabs as parameters
        /// </summary>
        /// <param name="tabs"></param>
        /// <returns></returns>
        private static async Task <bool> UpdateItemsInStash(IEnumerable <CommunityLibSettings.StringEntry> tabs)
        {
            foreach (var tab in tabs.Select(d => d.Name).Where(tab => !string.IsNullOrEmpty(tab)))
            {
                if (await UpdateSpecificTab(tab))
                {
                    continue;
                }
                CommunityLib.Log.Info($"[CommunityLib][UpdateItemsInStash (specific)] An error happend when caching the tab \"{tab}\"");
                //return false;
            }

            ItemsInStashAlreadyCached = true;
            await Coroutines.LatencyWait();

            return(true);
        }
示例#5
0
        public static async Task <bool> WaitForCursorToHaveItem(int timeout = 5000)
        {
            var sw = Stopwatch.StartNew();

            while (!LokiPoe.InstanceInfo.GetPlayerInventoryItemsBySlot(InventorySlot.Cursor).Any())
            {
                CommunityLib.Log.InfoFormat("[CommunityLib][WaitForCursorToHaveItem] Waiting for the cursor to have an item.");
                await Coroutines.LatencyWait();

                if (sw.ElapsedMilliseconds > timeout)
                {
                    CommunityLib.Log.InfoFormat("[CommunityLib][WaitForCursorToHaveItem] Timeout while waiting for the cursor to contain an item.");
                    return(false);
                }
            }
            return(true);
        }
示例#6
0
        /// <summary>
        /// This coroutine attempts to highlight and interact with an object.
        /// Interaction only takes place if the object is highlighted or an object of type T is.
        /// </summary>
        /// <typeparam name="T">The type of object acceptable to be highlighted if the intended target is not highlighted.</typeparam>
        /// <param name="holdCtrl">Should control be held? For area transitions.</param>
        /// <param name="obj">The object to interact with.</param>
        /// <returns>true on success and false on failure.</returns>
        public static async Task <bool> InteractWith <T>(NetworkObject obj, bool holdCtrl = false)
        {
            if (obj == null)
            {
                CommunityLib.Log.ErrorFormat("[InteractWith] The object is null.");
                return(false);
            }

            var id = obj.Id;

            CommunityLib.Log.DebugFormat($"[InteractWith] Now attempting to highlight {id}.");
            await Coroutines.FinishCurrentAction();

            if (!LokiPoe.Input.HighlightObject(obj))
            {
                CommunityLib.Log.ErrorFormat("[InteractWith] The target could not be highlighted.");
                return(false);
            }

            var target = LokiPoe.InGameState.CurrentTarget;

            if (target != obj && !(target is T))
            {
                CommunityLib.Log.ErrorFormat("[InteractWith] The target highlight has been lost.");
                return(false);
            }

            CommunityLib.Log.DebugFormat($"[InteractWith] Now attempting to interact with {id}.");

            if (holdCtrl)
            {
                LokiPoe.ProcessHookManager.SetKeyState(Keys.ControlKey, 0x8000);
            }

            LokiPoe.Input.ClickLMB();
            await Coroutines.LatencyWait();

            await Coroutines.FinishCurrentAction(false);

            LokiPoe.ProcessHookManager.ClearAllKeyStates();

            return(true);
        }
示例#7
0
        /// <summary>
        /// This coroutines waits for the character to change positions from a local area transition.
        /// </summary>
        /// <param name="position">The starting position.</param>
        /// <param name="delta">The change in position required.</param>
        /// <param name="timeout">How long to wait before the coroutine fails.</param>
        /// <returns>true on success, and false on failure.</returns>
        public static async Task <bool> WaitForPositionChange(Vector2i position, int delta = 30, int timeout = 5000)
        {
            CommunityLib.Log.DebugFormat("[WaitForPositionChange]");

            var sw = Stopwatch.StartNew();

            while (LokiPoe.MyPosition.Distance(position) < delta)
            {
                if (sw.ElapsedMilliseconds > timeout)
                {
                    CommunityLib.Log.ErrorFormat("[WaitForLargerPositionChange] Timeout.");
                    return(false);
                }

                CommunityLib.Log.DebugFormat("[WaitForLargerPositionChange] We have been waiting {0} for an area change.", sw.Elapsed);

                await Coroutines.LatencyWait();
            }

            return(true);
        }
示例#8
0
        /// <summary>
        /// This coroutine waits for the instance manager to open.
        /// </summary>
        /// <param name="timeout">How long to wait before the coroutine fails.</param>
        /// <returns>true on succes and false on failure.</returns>
        public static async Task <bool> WaitForInstanceManager(int timeout = 1000)
        {
            CommunityLib.Log.DebugFormat("[WaitForInstanceManager]");

            var sw = Stopwatch.StartNew();

            while (!LokiPoe.InGameState.InstanceManagerUi.IsOpened)
            {
                if (sw.ElapsedMilliseconds > timeout)
                {
                    CommunityLib.Log.ErrorFormat("[WaitForInstanceManager] Timeout.");
                    return(false);
                }

                CommunityLib.Log.DebugFormat("[WaitForInstanceManager] We have been waiting {0} for the instance manager to open.",
                                             sw.Elapsed);

                await Coroutines.LatencyWait();
            }

            return(true);
        }
示例#9
0
        /// <summary>
        /// This coroutines waits for the character to change areas.
        /// </summary>
        /// <param name="original">The starting area's hash.</param>
        /// <param name="timeout">How long to wait before the coroutine fails.</param>
        /// <returns>true on success, and false on failure.</returns>
        public static async Task <bool> WaitForAreaChange(uint original, int timeout = 30000)
        {
            CommunityLib.Log.DebugFormat("[WaitForAreaChange]");

            var sw = Stopwatch.StartNew();

            while (LokiPoe.LocalData.AreaHash == original)
            {
                if (sw.ElapsedMilliseconds > timeout)
                {
                    CommunityLib.Log.ErrorFormat("[WaitForAreaChange] Timeout.");
                    return(false);
                }

                CommunityLib.Log.DebugFormat("[WaitForAreaChange] We have been waiting {0} for an area change.", sw.Elapsed);
                await Coroutines.LatencyWait();

                await Coroutine.Sleep(1000);
            }

            return(true);
        }
示例#10
0
        /// <summary>
        /// Opens the inventory panel.
        /// </summary>
        /// <returns></returns>
        public static async Task <bool> OpenInventoryPanel(int timeout = 10000)
        {
            CommunityLib.Log.DebugFormat("[OpenInventoryPanel]");

            var sw = Stopwatch.StartNew();

            // Make sure we close all blocking windows so we can actually open the inventory.
            if (!LokiPoe.InGameState.InventoryUi.IsOpened)
            {
                await Coroutines.CloseBlockingWindows();
            }

            // Open the inventory panel like a player would.
            while (!LokiPoe.InGameState.InventoryUi.IsOpened)
            {
                CommunityLib.Log.DebugFormat("[OpenInventoryPanel] The InventoryUi is not opened. Now opening it.");

                if (sw.ElapsedMilliseconds > timeout)
                {
                    CommunityLib.Log.ErrorFormat("[OpenInventoryPanel] Timeout.");
                    return(false);
                }

                if (LokiPoe.Me.IsDead)
                {
                    CommunityLib.Log.ErrorFormat("[OpenInventoryPanel] We are now dead.");
                    return(false);
                }

                LokiPoe.Input.SimulateKeyEvent(LokiPoe.Input.Binding.open_inventory_panel, true, false, false);
                await Coroutines.LatencyWait(2);

                await Coroutines.ReactionWait();
            }

            return(true);
        }
示例#11
0
        /// <summary>
        /// This coroutine interacts with an area transition in order to change areas. It assumes
        /// you are in interaction range with the area transition itself. It can be used both in town,
        /// and out of town, given the previous conditions are met.
        /// </summary>
        /// <param name="obj">The area transition object to take.</param>
        /// <param name="newInstance">Should a new instance be created.</param>
        /// <param name="isLocal">Is the area transition local? In other words, should the couroutine not wait for an area change.</param>
        /// <param name="maxInstances">The max number of instance entries allowed to Join a new instance or -1 to not check.</param>
        /// <returns>A TakeAreaTransitionError that describes the result.</returns>
        public static async Task <Results.TakeAreaTransitionError> TakeAreaTransition(NetworkObject obj, bool newInstance,
                                                                                      int maxInstances,
                                                                                      bool isLocal = false)
        {
            CommunityLib.Log.InfoFormat("[TakeAreaTransition] {0} {1} {2}", obj.Name, newInstance ? "(new instance)" : "",
                                        isLocal ? "(local)" : "");

            await Coroutines.CloseBlockingWindows();

            await Coroutines.FinishCurrentAction();

            var hash = LokiPoe.LocalData.AreaHash;
            var pos  = LokiPoe.MyPosition;

            if (!await InteractWith(obj, newInstance))
            {
                return(Results.TakeAreaTransitionError.InteractFailed);
            }

            if (newInstance)
            {
                if (!await WaitForInstanceManager(5000))
                {
                    LokiPoe.ProcessHookManager.ClearAllKeyStates();

                    return(Results.TakeAreaTransitionError.InstanceManagerDidNotOpen);
                }

                LokiPoe.ProcessHookManager.ClearAllKeyStates();

                await Coroutines.LatencyWait();

                await Coroutine.Sleep(1000); // Let the gui stay open a bit before clicking too fast.

                if (LokiPoe.InGameState.InstanceManagerUi.InstanceCount >= maxInstances)
                {
                    return(Results.TakeAreaTransitionError.TooManyInstances);
                }

                var nierr = LokiPoe.InGameState.InstanceManagerUi.JoinNewInstance();
                if (nierr != LokiPoe.InGameState.JoinInstanceResult.None)
                {
                    CommunityLib.Log.ErrorFormat("[TakeAreaTransition] InstanceManagerUi.JoinNew returned {0}.", nierr);
                    return(Results.TakeAreaTransitionError.JoinNewFailed);
                }

                // Wait for the action to take place first.
                await Coroutines.LatencyWait();

                await Coroutines.ReactionWait();
            }

            if (isLocal)
            {
                if (!await WaitForPositionChange(pos))
                {
                    CommunityLib.Log.ErrorFormat("[TakeAreaTransition] WaitForPositionChange failed.");
                    return(Results.TakeAreaTransitionError.WaitForAreaChangeFailed);
                }
            }
            else
            {
                if (!await Areas.WaitForAreaChange(hash))
                {
                    CommunityLib.Log.ErrorFormat("[TakeAreaTransition] WaitForAreaChange failed.");
                    return(Results.TakeAreaTransitionError.WaitForAreaChangeFailed);
                }
            }

            return(Results.TakeAreaTransitionError.None);
        }
示例#12
0
        /// <summary>
        /// This coroutine creates a portal to town from a Portal Scroll in the inventory.
        /// </summary>
        /// <returns>true if the Portal Scroll was used and false otherwise.</returns>
        public static async Task <bool> CreatePortalToTown()
        {
            if (LokiPoe.Me.IsInTown)
            {
                CommunityLib.Log.ErrorFormat("[CreatePortalToTown] Town portals are not allowed in town.");
                return(false);
            }

            if (LokiPoe.Me.IsInHideout)
            {
                CommunityLib.Log.ErrorFormat("[CreatePortalToTown] Town portals are not allowed in hideouts.");
                return(false);
            }

            if (LokiPoe.CurrentWorldArea.IsMissionArea || LokiPoe.CurrentWorldArea.IsDenArea ||
                LokiPoe.CurrentWorldArea.IsRelicArea || LokiPoe.CurrentWorldArea.IsDailyArea)
            {
                CommunityLib.Log.ErrorFormat("[CreatePortalToTown] Town Portals are not allowed in mission areas.");
                return(false);
            }

            await Coroutines.FinishCurrentAction();

            await Coroutines.CloseBlockingWindows();

            var portalSkill = LokiPoe.InGameState.SkillBarHud.Skills.FirstOrDefault(s => s.Name == "Portal");

            if (portalSkill != null && portalSkill.CanUse(true))
            {
                CommunityLib.Log.DebugFormat("[CreatePortalToTown] We have a Portal skill on the skill bar. Now using it.");

                var err = LokiPoe.InGameState.SkillBarHud.Use(portalSkill.Slot, false);
                CommunityLib.Log.InfoFormat($"[CreatePortalToTown] SkillBarHud.Use returned {err}.");

                await Coroutines.LatencyWait();

                await Coroutines.FinishCurrentAction();

                if (err == LokiPoe.InGameState.UseResult.None)
                {
                    var sw = Stopwatch.StartNew();
                    while (sw.ElapsedMilliseconds < 3000)
                    {
                        var portal = LokiPoe.ObjectManager.Objects.OfType <Portal>().FirstOrDefault(p => p.Distance < 50);
                        if (portal != null)
                        {
                            return(true);
                        }

                        CommunityLib.Log.DebugFormat("[CreatePortalToTown] No portal was detected yet, waiting...");
                        await Coroutines.LatencyWait();
                    }
                }
            }

            CommunityLib.Log.DebugFormat("[CreatePortalToTown] Now opening the inventory panel.");

            // We need the inventory panel open.
            if (!await OpenInventoryPanel())
            {
                return(false);
            }

            await Coroutines.ReactionWait();

            CommunityLib.Log.DebugFormat("[CreatePortalToTown] Now searching the main inventory for a Portal Scroll.");

            var item = LokiPoe.InstanceInfo.GetPlayerInventoryItemsBySlot(InventorySlot.Main).FirstOrDefault(i => i.Name == "Portal Scroll");

            if (item == null)
            {
                CommunityLib.Log.ErrorFormat("[CreatePortalToTown] There are no Portal Scrolls in the inventory.");
                return(false);
            }

            CommunityLib.Log.DebugFormat("[CreatePortalToTown] Now using the Portal Scroll.");

            var err2 = LokiPoe.InGameState.InventoryUi.InventoryControl_Main.UseItem(item.LocalId);

            if (err2 != UseItemResult.None)
            {
                CommunityLib.Log.ErrorFormat($"[CreatePortalToTown] UseItem returned {err2}.");
                return(false);
            }

            await Coroutines.LatencyWait();

            await Coroutines.ReactionWait();

            await Coroutines.CloseBlockingWindows();

            return(true);
        }
示例#13
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);
        }
示例#14
0
        /// <summary>
        /// This functions is meant to use an item on another one, for identification, chancing, anything you can think about
        /// It also supports the +X% quality using stones/scraps
        /// </summary>
        /// <param name="sourceWrapper">The source (inventory) that's holding the item meant to be used</param>
        /// <param name="sourceItem">The item meant to be used</param>
        /// <param name="destinationWrapper">The source (inventory) holding the item meant to be altered</param>
        /// <param name="destinationItem">The item menant to be altered</param>
        /// <param name="d">Delegate/Condition to stop using item</param>
        /// <returns>ApplyCursorResult enum entry</returns>
        public static async Task <ApplyCursorResult> UseItemOnItem(InventoryControlWrapper sourceWrapper, Item sourceItem, InventoryControlWrapper destinationWrapper, Item destinationItem, StopUsingDelegate d = null)
        {
            // If Any of these args are null, throw an application-level exception
            if (sourceWrapper == null)
            {
                throw new ArgumentNullException(nameof(sourceWrapper));
            }
            if (sourceItem == null)
            {
                throw new ArgumentNullException(nameof(sourceItem));
            }
            if (destinationWrapper == null)
            {
                throw new ArgumentNullException(nameof(destinationWrapper));
            }
            if (destinationItem == null)
            {
                throw new ArgumentNullException(nameof(destinationItem));
            }

            // If the item is not modifiable, prevent the logic to be executed
            if (destinationItem.IsCorrupted || destinationItem.IsMirrored)
            {
                CommunityLib.Log.DebugFormat("[CommunityLib] We can\'t alter the item (Corrupted/Mirrored). UnsupportedItem");
                return(ApplyCursorResult.UnsupportedItem);
            }

            if (destinationItem.HasSkillGemsEquipped && sourceItem.FullName == "Jeweller's Orb")
            {
                CommunityLib.Log.DebugFormat("[CommunityLib] We can't change sockets on the item (Has skill gems in it). UnsupportedItem");
                return(ApplyCursorResult.UnsupportedItem);
            }

            var onCursor = sourceWrapper.UseItem(sourceItem.LocalId);

            // We assume it's currency stash tab, do not use LocalId with it
            if (onCursor == UseItemResult.Unsupported)
            {
                CommunityLib.Log.DebugFormat("[CommunityLib] Failed to use item on item. Unsupported");
                onCursor = sourceWrapper.UseItem();
            }

            await Coroutines.LatencyWait();

            // If something else than None is returned, the item can't be put on cursor properly
            if (onCursor != UseItemResult.None)
            {
                if (!await Inputs.WaitForCursorToHaveItem())
                {
                    CommunityLib.Log.ErrorFormat($"[CommunityLib] Failed to use item on item. OnCursor: {onCursor}. Returning item not found");
                    return(ApplyCursorResult.ItemNotFound);
                }
            }

            await Coroutines.LatencyWait();

            // First, we put the item on cursor to start applying
            var err = InventoryControlWrapper.BeginApplyCursor(true);

            if (err != ApplyCursorResult.None)
            {
                CommunityLib.Log.Error($"[CommunityLib] Error returned for BeginApplyCursor : {err}");
                return(ApplyCursorResult.ProcessHookManagerNotEnabled);
            }

            // We store the destination item's location to make sure it has been applied or the delegate (lower in the code) is valid
            var itemLocation = destinationItem.LocationTopLeft;
            int useCount     = 0;

            while (true)
            {
                var initialId = destinationItem.LocalId;

                // Apply item on cursor to the destination item
                err = destinationWrapper.ApplyCursorTo(destinationItem.LocalId);
                //Destination is in utility currency slot?
                if (err == ApplyCursorResult.Unsupported)
                {
                    err = destinationWrapper.ApplyCursorTo();
                }

                // If the error is different of None, break the execution and return the error
                if (err != ApplyCursorResult.None)
                {
                    break;
                }

                // Check if the item has been modified on memory-side
                if (!await WaitForItemToChange(destinationWrapper, initialId))
                {
                    break;
                }

                await Coroutines.LatencyWait();

                //await Coroutines.ReactionWait();

                // If the delegate is null, that means our processing is done, break the loop to return None
                if (d == null)
                {
                    break;
                }

                // We increment usecount to make it usable in delegate
                useCount++;

                // Refresh item to test the delegate (or condition)
                destinationItem = destinationWrapper.Inventory.GetItemAtLocation(itemLocation.X, itemLocation.Y);
                if (d.Invoke(destinationItem, useCount))
                {
                    break;
                }
            }

            // End up the item application
            var err2 = InventoryControlWrapper.EndApplyCursor();
            await Coroutine.Yield();

            await Inputs.WaitForCursorToBeEmpty();

            // IF an error is returned, let caller know
            if (err2 != ApplyCursorResult.None)
            {
                CommunityLib.Log.Error($"[CommunityLib] Error returned for EndApplyCursor : {err2}");
                return(ApplyCursorResult.ProcessHookManagerNotEnabled);
            }

            if (err != ApplyCursorResult.None)
            {
                CommunityLib.Log.ErrorFormat($"[CommunityLib] Failed to use item on item. Error: {err}");
            }
            return(err);
        }
示例#15
0
        /// <summary>
        /// Generic FastMove using new Inv Wrapper
        /// The inventory you refer is theinventory that will be used for moving the item from
        /// </summary>
        /// <param name="inv">This is the location where the item is picked up (can be stash or whatever you want)</param>
        /// <param name="id">This is the item localid</param>
        /// <param name="retries">Number of max fastmove attempts</param>
        /// <param name="breakFunc">If specified condition return true, FastMove will canceled and false will be returned</param>
        /// <returns>FastMoveResult enum entry</returns>
        public static async Task <bool> FastMove(InventoryControlWrapper inv, int id, int retries = 3, Func <bool> breakFunc = null)
        {
            // If the inventory is null for reasons, throw ana application-level error
            if (inv == null)
            {
                throw new ArgumentNullException(nameof(inv));
            }

            // Here the idea is to make a first fastmove attempt to get an error
            // If the error is different of None, return the error
            var err = inv.FastMove(id);

            //We assume it's currency stash tab, do not use LocalId with it
            if (err == FastMoveResult.Unsupported)
            {
                err = inv.FastMove();
            }

            if (err != FastMoveResult.None)
            {
                CommunityLib.Log.ErrorFormat("[CommunityLib][FastMove] FastMove has returned an error : {0}", err);
                return(false);
            }

            await Coroutines.LatencyWait();

            await Coroutines.ReactionWait();

            // The idea is to have a maximum of tries, but we don't want to spam them.
            // A Timer is started to "cool-off" the tries and a random lapse is calculated between each checks
            var nextfastmovetimer = Stopwatch.StartNew();
            var nextFastMove      = LokiPoe.Random.Next(2500, 4000);
            int nextFastMoveTries = 0;

            while (nextFastMoveTries < retries)
            {
                if (breakFunc != null)
                {
                    if (breakFunc())
                    {
                        return(false);
                    }
                }

                // Verifying if the item exists in the source inventory
                // If not, the item has been moved return true
                var itemExists = inv.Inventory.GetItemById(id);
                if (itemExists == null)
                {
                    await Coroutines.ReactionWait();

                    return(true);
                }

                // If it exists, and the timer has reached the random lapse we calculated above,
                // Attempt to make a new move
                if (nextfastmovetimer.ElapsedMilliseconds > nextFastMove)
                {
                    CommunityLib.Log.DebugFormat("[CommunityLib][FastMove] Attempt to fastmove ({0}/{1})", nextFastMoveTries, retries);
                    var error = inv.FastMove(id);
                    if (error == FastMoveResult.Unsupported)
                    {
                        inv.FastMove();
                    }

                    await Coroutines.LatencyWait();

                    await Coroutines.ReactionWait();

                    nextFastMove = LokiPoe.Random.Next(2500, 4000);
                    nextfastmovetimer.Restart();
                    nextFastMoveTries++;
                }

                await Coroutine.Sleep(20);
            }

            // It failed after the number of tries referenced, just return false.
            CommunityLib.Log.ErrorFormat("[CommunityLib][FastMove] Operation failed after {0} tries", retries);
            return(false);
        }
示例#16
0
        /// <summary>
        /// Implements the ability to handle a logic passed through the system.
        /// </summary>
        /// <param name="logic">The logic to be processed.</param>
        /// <returns>A LogicResult that describes the result..</returns>
        public async Task <LogicResult> Logic(Logic logic)
        {
            if (logic.Id == "hook_post_combat")
            {
                // Don't update while we are not in the game.
                if (!LokiPoe.IsInGame)
                {
                    return(LogicResult.Unprovided);
                }

                // When the game is paused, don't try to run.
                if (LokiPoe.InstanceInfo.IsGamePaused)
                {
                    return(LogicResult.Unprovided);
                }

                // Don't try to do anything when the escape state is active.
                if (LokiPoe.StateManager.IsEscapeStateActive)
                {
                    return(LogicResult.Unprovided);
                }

                // Don't level skill gems if we're dead.
                if (LokiPoe.Me.IsDead)
                {
                    return(LogicResult.Unprovided);
                }

                // Can't level skill gems under this scenario either.
                if (LokiPoe.InGameState.IsTopMostOverlayActive)
                {
                    return(LogicResult.Unprovided);
                }

                // Can't level skill gems under this scenario either.
                if (LokiPoe.InGameState.SkillsUi.IsOpened)
                {
                    return(LogicResult.Unprovided);
                }

                // Only check for skillgem leveling at a fixed interval.
                if (!_needsToUpdate && !_levelWait.IsFinished)
                {
                    return(LogicResult.Unprovided);
                }

                Func <Inventory, Item, Item, bool> eval = (inv, holder, gem) =>
                {
                    // Ignore any "globally ignored" gems. This just lets the user move gems around
                    // equipment, without having to worry about where or what it is.
                    if (ContainsHelper(gem.Name))
                    {
                        if (GemLevelerSettings.Instance.DebugStatements)
                        {
                            Log.DebugFormat("[LevelSkillGemTask] {0} => {1}.", gem.Name, "GlobalNameIgnoreList");
                        }
                        return(false);
                    }

                    // Now look though the list of skillgem strings to level, and see if the current gem matches any of them.
                    var ss = string.Format("{0} [{1}: {2}]", gem.Name, inv.PageSlot, holder.GetSocketIndexOfGem(gem));
                    foreach (var str in GemLevelerSettings.Instance.SkillGemsToLevelList)
                    {
                        if (str.Equals(ss, StringComparison.OrdinalIgnoreCase))
                        {
                            if (GemLevelerSettings.Instance.DebugStatements)
                            {
                                Log.DebugFormat("[LevelSkillGemTask] {0} => {1}.", gem.Name, str);
                            }
                            return(true);
                        }
                    }

                    // No match, we shouldn't level this gem.
                    return(false);
                };

                // If we have icons on the hud to process.
                if (LokiPoe.InGameState.SkillGemHud.AreIconsDisplayed)
                {
                    // If the InventoryUi is already opened, skip this logic and let the next set run.
                    if (!LokiPoe.InGameState.InventoryUi.IsOpened)
                    {
                        // We need to close blocking windows.
                        await Coroutines.CloseBlockingWindows();

                        // We need to let skills finish casting, because of 2.6 changes.
                        await Coroutines.FinishCurrentAction();

                        await Coroutines.LatencyWait();

                        await Coroutines.ReactionWait();

                        var res = LokiPoe.InGameState.SkillGemHud.HandlePendingLevelUps(eval);

                        Log.InfoFormat("[LevelSkillGemTask] SkillGemHud.HandlePendingLevelUps returned {0}.", res);

                        if (res == LokiPoe.InGameState.HandlePendingLevelUpResult.GemDismissed ||
                            res == LokiPoe.InGameState.HandlePendingLevelUpResult.GemLeveled)
                        {
                            await Coroutines.LatencyWait();

                            await Coroutines.ReactionWait();

                            return(LogicResult.Provided);
                        }
                    }
                }

                if (_needsToUpdate || LokiPoe.InGameState.InventoryUi.IsOpened)
                {
                    if (LokiPoe.InGameState.InventoryUi.IsOpened)
                    {
                        _needsToCloseInventory = false;
                    }
                    else
                    {
                        _needsToCloseInventory = true;
                    }

                    // We need the inventory panel open.
                    if (!await OpenInventoryPanel())
                    {
                        Log.ErrorFormat("[LevelSkillGemTask] OpenInventoryPanel failed.");
                        return(LogicResult.Provided);
                    }

                    // If we have icons on the inventory ui to process.
                    // This is only valid when the inventory panel is opened.
                    if (LokiPoe.InGameState.InventoryUi.AreIconsDisplayed)
                    {
                        var res = LokiPoe.InGameState.InventoryUi.HandlePendingLevelUps(eval);

                        Log.InfoFormat("[LevelSkillGemTask] InventoryUi.HandlePendingLevelUps returned {0}.", res);

                        if (res == LokiPoe.InGameState.HandlePendingLevelUpResult.GemDismissed ||
                            res == LokiPoe.InGameState.HandlePendingLevelUpResult.GemLeveled)
                        {
                            await Coroutines.LatencyWait();

                            await Coroutines.ReactionWait();

                            return(LogicResult.Provided);
                        }
                    }
                }

                // Just wait 5-10s between checks.
                _levelWait.Reset(TimeSpan.FromMilliseconds(LokiPoe.Random.Next(5000, 10000)));

                //if (_needsToCloseInventory)
                {
                    await Coroutines.CloseBlockingWindows();

                    _needsToCloseInventory = false;
                }

                _needsToUpdate = false;
            }

            return(LogicResult.Unprovided);
        }
示例#17
0
        public static async Task <Results.ClearCursorResults> ClearCursorTask(int maxTries = 3)
        {
            var cursMode = LokiPoe.InGameState.CursorItemOverlay.Mode;

            if (cursMode == LokiPoe.InGameState.CursorItemModes.None)
            {
                CommunityLib.Log.DebugFormat("[CommunityLib][ClearCursorTask] Nothing is on cursor, continue execution");
                return(Results.ClearCursorResults.None);
            }

            if (cursMode == LokiPoe.InGameState.CursorItemModes.VirtualMove || cursMode == LokiPoe.InGameState.CursorItemModes.VirtualUse)
            {
                CommunityLib.Log.DebugFormat("[CommunityLib][ClearCursorTask] VirtualMode detected, pressing escape to clear");
                LokiPoe.Input.SimulateKeyEvent(Keys.Escape, true, false, false);
                return(Results.ClearCursorResults.None);
            }

            var cursorhasitem = LokiPoe.InGameState.CursorItemOverlay.Item;
            // there is a item on the cursor let clear it
            int attempts = 0;

            while (cursorhasitem != null && attempts < maxTries)
            {
                if (attempts > maxTries)
                {
                    return(Results.ClearCursorResults.MaxTriesReached);
                }

                if (!LokiPoe.InGameState.InventoryUi.IsOpened)
                {
                    await LibCoroutines.OpenInventoryPanel();

                    await Coroutines.LatencyWait();

                    await Coroutines.ReactionWait();

                    if (!LokiPoe.InGameState.InventoryUi.IsOpened)
                    {
                        return(Results.ClearCursorResults.InventoryNotOpened);
                    }
                }

                int col, row;
                if (!LokiPoe.InGameState.InventoryUi.InventoryControl_Main.Inventory.CanFitItem(cursorhasitem.Size, out col, out row))
                {
                    CommunityLib.Log.ErrorFormat("[CommunityLib][ClearCursorTask] Now stopping the bot because it cannot continue.");
                    BotManager.Stop();
                    return(Results.ClearCursorResults.NoSpaceInInventory);
                }

                var res = LokiPoe.InGameState.InventoryUi.InventoryControl_Main.PlaceCursorInto(col, row);
                if (res == PlaceCursorIntoResult.None)
                {
                    if (!await WaitForCursorToBeEmpty())
                    {
                        CommunityLib.Log.ErrorFormat("[CommunityLib][ClearCursorTask] WaitForCursorToBeEmpty failed.");
                    }

                    await Coroutines.ReactionWait();

                    return(Results.ClearCursorResults.None);
                }

                CommunityLib.Log.DebugFormat("[CommunityLib][ClearCursorTask] Placing item into inventory failed, Err : {0}", res);
                switch (res)
                {
                case PlaceCursorIntoResult.ItemWontFit:
                    return(Results.ClearCursorResults.NoSpaceInInventory);

                case PlaceCursorIntoResult.NoItemToMove:
                    return(Results.ClearCursorResults.None);
                }

                await Coroutine.Sleep(3000);

                await Coroutines.LatencyWait();

                await Coroutines.ReactionWait();

                cursorhasitem = LokiPoe.InGameState.CursorItemOverlay.Item;
                attempts++;
            }

            return(Results.ClearCursorResults.None);
        }
示例#18
0
        /// <summary>
        /// The function will use chat to move to hideout
        /// </summary>
        /// <param name="retries">Number of max fastmove attempts. One is 8-16s timeout</param>
        /// <returns></returns>
        public static async Task <Results.FastGoToHideoutResult> FastGoToHideout(int retries = 3)
        {
            // No need to proceed if we are already there.
            if (LokiPoe.Me.IsInHideout)
            {
                return(Results.FastGoToHideoutResult.None);
            }

            //I need to be in town to go to hideout using this method
            if (!LokiPoe.Me.IsInTown)
            {
                return(Results.FastGoToHideoutResult.NotInTown);
            }

            LokiPoe.InGameState.ChatPanel.Commands.hideout();
            //Chat.SendChatMsg("/hideout", false);
            await Coroutines.LatencyWait();

            await Coroutines.ReactionWait();

            // The idea is to have a maximum of tries, but we don't want to spam them.
            // A Timer is started to "cool-off" the tries and a random lapse is calculated between each checks
            var nextTimer    = Stopwatch.StartNew();
            var nextTry      = LokiPoe.Random.Next(8000, 16000);
            int nextTryTries = 0;

            while (nextTryTries < retries)
            {
                if (LokiPoe.Me.IsInHideout)
                {
                    await Coroutines.LatencyWait();

                    await Coroutines.ReactionWait();

                    return(Results.FastGoToHideoutResult.None);
                }

                //Thanks pushedx for the function. I think I don't need it but I'll put a comment here so you'll feel better Kappa
                //LokiPoe.InGameState.IsEnteringAreaTextShown

                //User have no hideout
                var noHideoutMessage = Chat.GetNewChatMessages().Any(d => d.Message.Contains(Dat.LookupBackendError(BackendErrorEnum.NoHideout).Text));
                if (noHideoutMessage)
                {
                    return(Results.FastGoToHideoutResult.NoHideout);
                }

                // If it exists, and the timer has reached the random lapse we calculated above,
                if (nextTimer.ElapsedMilliseconds > nextTry)
                {
                    CommunityLib.Log.DebugFormat("[CommunityLib][FastGoToHideout] Attempt to fastmove ({0}/{1})", nextTryTries, retries);
                    if (LokiPoe.IsInGame)
                    {
                        LokiPoe.InGameState.ChatPanel.Commands.hideout();
                    }

                    await Coroutines.LatencyWait();

                    await Coroutines.ReactionWait();

                    nextTry = LokiPoe.Random.Next(8000, 16000);
                    nextTimer.Restart();
                    nextTryTries++;
                }

                //No need to go that fast
                await Coroutine.Sleep(200);
            }

            CommunityLib.Log.ErrorFormat("[CommunityLib][FastGoToHideout] Operation failed after {0} tries", retries);
            return(Results.FastGoToHideoutResult.TimeOut);
        }
示例#19
0
        /// <summary>
        /// This function iterates through the stash to find an item by name
        /// If a tab is reached and the item is found, GUI will be stopped on this tab so you can directly interact with it.
        /// </summary>
        /// <param name="condition">Condition to pass item through</param>
        /// <returns></returns>
        public static async Task <Tuple <Results.FindItemInTabResult, CachedItemObject> > FindTabContainingItem(CommunityLib.FindItemDelegate condition)
        {
            // If stash isn't opened, abort this and return
            if (!await OpenStashTabTask())
            {
                return(new Tuple <Results.FindItemInTabResult, CachedItemObject>(Results.FindItemInTabResult.GuiNotOpened, null));
            }

            // If we fail to go to first tab, return
            // if (GoToFirstTab() != SwitchToTabResult.None)
            //     return new Tuple<Results.FindItemInTabResult, StashItem>(Results.FindItemInTabResult.GoToFirstTabFailed, null);

            foreach (var tabName in StashUI.TabControl.TabNames)
            {
                // If the item has no occurences in this tab, switch to the next one
                var it = FindItemInStashTab(condition);
                if (it == null)
                {
                    // On last tab? break execution
                    if (StashUI.TabControl.IsOnLastTab)
                    {
                        break;
                    }

                    int switchAttemptsPerTab = 0;
                    while (true)
                    {
                        // If we tried 3 times to switch and failed, return
                        if (switchAttemptsPerTab > 2)
                        {
                            return(new Tuple <Results.FindItemInTabResult, CachedItemObject>(Results.FindItemInTabResult.SwitchToTabFailed, null));
                        }

                        var switchTab = StashUI.TabControl.SwitchToTabMouse(tabName);

                        // If the switch went fine, keep searching
                        if (switchTab == SwitchToTabResult.None)
                        {
                            break;
                        }

                        switchAttemptsPerTab++;
                        await Coroutines.LatencyWait();

                        await Coroutines.ReactionWait();
                    }

                    // Keep searching...
                    await Coroutines.LatencyWait();

                    await Coroutines.ReactionWait();

                    continue;
                }

                // We Found a tab, return informations
                return(new Tuple <Results.FindItemInTabResult, CachedItemObject>(Results.FindItemInTabResult.None, it));
            }

            return(new Tuple <Results.FindItemInTabResult, CachedItemObject>(Results.FindItemInTabResult.ItemNotFoundInTab, null));
        }