Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

Sign up now!

Bug Multiple actions on one leaf

Joined
Feb 23, 2019
Messages
34
I'm trying to perform multiple actions in one LeafTask as follows:


Code:
        GameObject trap = GameObjects.newQuery().names("Shaking box").reachable().results().nearest();
        SpriteItem invTrap = Inventory.newQuery().names("Box trap").results().random();

        if(trap != null && invTrap != null){

            System.out.println("trap position: " + trap.getPosition().toString());

            // get location of nearest trap
            Coordinate trapCoord = trap.getPosition();

            // check trap by clicking
            if (trap.interact("Check")) {
                Execution.delayUntil(() -> Vars.player.getAnimationId() != -1, 5000);
            }

            // move back to checked trap position
            if (trapCoord.interact("Walk here")) {
                Execution.delayUntil(() -> Vars.player.getAnimationId() != -1, 5000);
            }

            // replace trap
            if(invTrap.interact("Lay")){
                Execution.delayUntil(() -> Vars.player.getAnimationId() != -1, 5000);
            }
        }

The results vary. Sometimes it will try to walk before it's finished checking the trap, other times it will try to walk where the trap was laid during the checking animation and drop the box trap on the current position rather than on the coord of the checked box trap.

Am I missing some sort of delay between these interactions, simply doing it wrong, or maybe this should be further broken down to more branches first?
 
The Omen
Joined
Dec 27, 2018
Messages
159
So a note on your structure, the use of multiple actions per loop (especially when written like this) is discouraged for the reasons it's failing. I'd strongly recommend splitting each action into its own task, because then you can properly define conditions for which they should execute at.

When checking a trap, your player may have to run, meaning your animation will stay at -1 for a brief second before interacting. This is what I assume is breaking your first delay and causing it to try to walk whilst you're checking. To combat this, you could add a reset condition which looks something like
Code:
 Execution.delayUntil(() -> Vars.player.getAnimationId() != -1, () -> Vars.player.isMoving(), 600, 1200);
. Notice I reduce the delay range too, incase of a missclick, your bot might idle for 5 seconds before trying to interact again. With resets and a shorter delay, you're able to pick yourself up quicker after an error.

When walking, I would delay until your Players current position is equal to the Trap's position, and delaying whilst moving (see code above for the "whilst moving" reset).

Whilst laying, you could delay until either A) The local players animation frame is above a certain integer (this is probably the quickest way to do it, but this breaks down if you implement tick-hunting) or B) Delaying until the position you're standing on contains an untriggered box trap. You could do this by getting your local player's position, and querying for objects on that position that go by the name "Box trap" (I'm not actually sure on the name, so don't use that). Using
Code:
!GameObjects.newQuery().on(localPosition).names("Box trap").actions("Dismantle").results().isEmpty();
checks if there's any box on that coordinate.

Good luck :)
 
Joined
Feb 23, 2019
Messages
34
So a note on your structure, the use of multiple actions per loop (especially when written like this) is discouraged for the reasons it's failing. I'd strongly recommend splitting each action into its own task, because then you can properly define conditions for which they should execute at.

When checking a trap, your player may have to run, meaning your animation will stay at -1 for a brief second before interacting. This is what I assume is breaking your first delay and causing it to try to walk whilst you're checking. To combat this, you could add a reset condition which looks something like
Code:
 Execution.delayUntil(() -> Vars.player.getAnimationId() != -1, () -> Vars.player.isMoving(), 600, 1200);
. Notice I reduce the delay range too, incase of a missclick, your bot might idle for 5 seconds before trying to interact again. With resets and a shorter delay, you're able to pick yourself up quicker after an error.

When walking, I would delay until your Players current position is equal to the Trap's position, and delaying whilst moving (see code above for the "whilst moving" reset).

Whilst laying, you could delay until either A) The local players animation frame is above a certain integer (this is probably the quickest way to do it, but this breaks down if you implement tick-hunting) or B) Delaying until the position you're standing on contains an untriggered box trap. You could do this by getting your local player's position, and querying for objects on that position that go by the name "Box trap" (I'm not actually sure on the name, so don't use that). Using
Code:
!GameObjects.newQuery().on(localPosition).names("Box trap").actions("Dismantle").results().isEmpty();
checks if there's any box on that coordinate.

Good luck :)


Thanks, this is a lot of good information.

Since I'm writing this as a tree bot and the structures that I've seen involve the leaf action being terminal, when you say to split each action into its own task do you mean its own leaf node? I assume that would require adding additional branches. Or perhaps there is a more common approach to handling multiple leaf tasks in succession?
 
The Omen
Joined
Dec 27, 2018
Messages
159
Thanks, this is a lot of good information.

Since I'm writing this as a tree bot and the structures that I've seen involve the leaf action being terminal, when you say to split each action into its own task do you mean its own leaf node? I assume that would require adding additional branches. Or perhaps there is a more common approach to handling multiple leaf tasks in succession?
Yes, split them into their own branch, have a "section" for your laying a trap movements like the ones you've mentioned in the first post.
 
Joined
Feb 23, 2019
Messages
34
Yes, split them into their own branch, have a "section" for your laying a trap movements like the ones you've mentioned in the first post.

My problem is that if each branch requires a success and failure transition then how am I supposed to transition from a simple action like checking a box trap? I didn't think that it would be a correct procedure to turn the action of checking into a branch, do the box trap check action in the validation, and return based on the trap's checked status where success would be to proceed with moving and relaying and failure would be to call this.validate() to reattempt the check. I'm trying to figure out the correct convention rather than hacking at this to work, but I feel like requiring everything but a simple action to be a binary choice makes it harder than it needs to be.
 
The Omen
Joined
Dec 27, 2018
Messages
159
1st Branch: Check a shaking box is present (GameObject trap = GameObjects.newQuery().names("Shaking box").reachable().results().nearest() != null)
2nd Branch: Check if there's no box on the square where there should be (maybe create an area around the character when the bot starts of get the user to set it in the ui). In this branch you should handle walking and box laying by checking if you're on the spot to plant and acting accordingly.

Place the 2nd branch after the 1st and you'll be fine.
 
Joined
Feb 23, 2019
Messages
34
1st Branch: Check a shaking box is present (GameObject trap = GameObjects.newQuery().names("Shaking box").reachable().results().nearest() != null)
2nd Branch: Check if there's no box on the square where there should be (maybe create an area around the character when the bot starts of get the user to set it in the ui). In this branch you should handle walking and box laying by checking if you're on the spot to plant and acting accordingly.

Place the 2nd branch after the 1st and you'll be fine.

This sounds like:
1st) Check for shaking box, check box -> 2nd branch
2nd) check if box is gone -> walk to spot, lay new trap

So it is a legal move to perform an action in the validate() method?
I see that the execute() method is final in the superclass BranchTask, so I can't override it in the 1st branch to perform an action in the standard sense. This leads me to the assumption that it would be legal to perform the shaking trap's checking action in the validate() method.

Additionally, based on the breakdown below: is it common practice to recall a previous branch as in the failure case of my 2nd branch?
On my first branch, I have: success (there is shaking box to check) -> 2nd branch
failure (no shaking box to check) -> branch looking for box to rebuild
On my second branch: success (box not on square) -> leaf: walk to, and lay trap on empty space
failure (box still on square) -> 1st branch​

EDIT: Actually, I think I'm just going to simplify this by doing a simple check on the shaking box as a leaf (basically cutting out the walking and relaying as I did in my first post) and allowing it to return to the root branch where it will do the inspection of the 5 chosen trap locations and lay a new trap if they're missing traps. I would still like to know the answers my questions above if you know the answers though: the legality of performing actions in the validate() method, and if it's a common practice to call a past branch in the case of something like a misclick.

 
Last edited:
Top