mineflayer-statemachine icon indicating copy to clipboard operation
mineflayer-statemachine copied to clipboard

Wildcard exit state for passive actions?

Open flowl opened this issue 3 years ago • 6 comments

I think it's useful to have exit states that apply to all parent:

new StateTransition({
    parent: null, // apply check to all parents?
    child: eatBehavior,
    shouldTransition: () => (this.bot.food <= 16 || this.bot.food < 20 && this.bot.health <= 16) && !this.bot.inLava()
 }),
new StateTransition({
    parent: eatBehavior, 
    child: this.getPreviousBehaviour(), // not sure about this yet :-)
    shouldTransition: () => eatBehavior.isFinished()
 }),

Currently, I am implementing passive actions either outside of the StateMachine, or very redundant inside multiple NestedStateMachines, neither feels like the best approach yet.

flowl avatar Nov 09 '20 18:11 flowl

After thinking more about it, maybe I simply need to reorder my states to always return to the root state machine if it can't fulfill the current nested states. That way, for example, if the bot is currently mining, it will stop on hunger or heavy dmg and resume after eating.

flowl avatar Nov 09 '20 21:11 flowl

Wildcard states can be a bit tricky, such as transitioning to itself or leaving a state too early, but I like the idea. Currently, this behavior can be kind of implemented using nested states by triggering the transition out of the parent state. This will automatically leave all child states as well. This is a bit safer, and you have a bit more control over when the transition takes place.

I'll leave this issue open though as a global wildcard sounds useful in some situations.

TheDudeFromCI avatar Nov 10 '20 20:11 TheDudeFromCI

Quick question on this, one of the things I have with my bot is it occasionally gets killed by mobs, I do have a fight mob state but Creepers can be a pain. What I would like to do is exit all states on death. Just trying to get my head around the possibility of this.

If I had the following nested states:

 new StateTransition({
          parent: idleStart,
          child: getMineState,
          name: "continue mining",
          shouldTransition: () => true
      }),
    
      // nothing left to mine
      new StateTransition({
          parent: getMineState,
          child: idleEnd,
          name: "all complete",
          shouldTransition: () => this.bot.isDead()
      }),

      new StateTransition({
          parent: getMineState,
          child: idleEnd,
          name: "all complete",
          shouldTransition: () => getMineState.isFinished(),
      }),

I am guessing this would cause problems as if the bot gets killed the root state would exit but it would not stop getMineState which would be prone to a crash as it would still be running. How do you gracefully deal with a Bot dying or being removed from a server without crash?

nicholasjackson avatar Dec 16 '20 20:12 nicholasjackson

Quick question on this, one of the things I have with my bot is it occasionally gets killed by mobs, I do have a fight mob state but Creepers can be a pain. What I would like to do is exit all states on death. Just trying to get my head around the possibility of this.

If I had the following nested states:

 new StateTransition({
          parent: idleStart,
          child: getMineState,
          name: "continue mining",
          shouldTransition: () => true
      }),
    
      // nothing left to mine
      new StateTransition({
          parent: getMineState,
          child: idleEnd,
          name: "all complete",
          shouldTransition: () => this.bot.isDead()
      }),

      new StateTransition({
          parent: getMineState,
          child: idleEnd,
          name: "all complete",
          shouldTransition: () => getMineState.isFinished(),
      }),

I am guessing this would cause problems as if the bot gets killed the root state would exit but it would not stop getMineState which would be prone to a crash as it would still be running. How do you gracefully deal with a Bot dying or being removed from a server without crash?

The code you provided is the correct way or dealing with it. Just make sure in your mining states, you properly cleanup in the onStateExited() function. So if the bot has a dig-block behavior, you tell the bot to cancel that it the state is exited before it's finished.

Also, quick note, death is usually an event based transition since the bot will try to respawn instantly after death. The shouldTransition here is only called once per physicTick and may be called after the bot has been dead but tried to update or the bot might have already respawned. Usually it's best to trigger manual transitions on death events.

TheDudeFromCI avatar Dec 17 '20 01:12 TheDudeFromCI

Amazing thank you @TheDudeFromCI, I am going to refactor now. On an unrelated note, I am really enjoying your videos on YouTube. As a side project, my buddy Erik and I have been working on a project to bring DevOps and Minecraft together.

https://www.youtube.com/c/HashiCraft/videos

nicholasjackson avatar Dec 17 '20 07:12 nicholasjackson

@nicholasjackson Oh thank you very much. I checked out a few of your videos and subbed,

TheDudeFromCI avatar Dec 17 '20 10:12 TheDudeFromCI