Detatch order of AppStates?

I have this:

class Game extends com.simsilica.state.CompositeAppState {
public Game(){
super (
  new ModelState(),
 //... other stuff
  new CollisionState());
}
}

CollisionState depends on ModelState (i.e. must start after ModelState and must disable before ModelState does).

Is there a clean way to achieve that?
Furthermore, it appears that when I detatch the Game, then the appstates are voided first (i.e. getState(ModelState.class) return null) and then the onDisable is called… is this the intended behavior?

Thanks!

If the state is detached then it is internally put into the “terminating” list but is no longer addressable through getState().

terminate order is called in the same order as initialize order.

In the rare case that your app state termination must refer to a specific state that was available during initialization then it should just keep a reference around.

In general, you will be happier if your states deal gracefully with missing dependent states… either through lazy initialization of those references or just nicer fallback behavior.

1 Like

Fine. So I am correct in saying that an appstate is “detached first and disabled next”?
And that it does this by design?

The source describes it’s order.

I’ve seen CompositeAppState used here and there, never really used it, however I have mirrored it’s behavior once or twice. Useful state. Maybe your answer lies there in its management of children.

1 Like

It looks like the state retains its “enabled” status even after being detached. Therefore, “detach” does NOT imply “onDisable” being called.

Ok, so I wrote my code under wrong assumptions and I need to adapt my logic accordingly.

States are detached on reverse order on CompositeAppState. Now my eyes are opening…

Yeah, it makes more sense but I couldn’t alter core JME without breaking things.

onDisable() is called before terminate if the state was enabled. Always. You can count on that lifecycle from BaseAppState… it’s the entire reason it exists.

You can setup thing that should exist for the life of the state in initialize() and clean them up in terminate().

You can do things in onEnable() that are only for when enabled. …and onDisable() for when things are disabled.

A lot of times I will create my spatials in initialize and add/remove them only in onEnable() and onDisable().

Edit: you can also look at most of my more complicated examples. They do this exactly.

1 Like

Is there a reliable way to know if an AppState is detached?

Something more elegant than testing if getState()==null

But that is the only way to know. If the state manager has it then it’s attached. If it doesn’t then it isn’t.

It might be in some state of initialized, enabled, etc… but if the state manager knows about it then it’s attached. If it doesn’t know about it then it isn’t attached.

You might try explaining what you are actually trying to do… because this starts to feel like a “how do I inject things into my stomach” conversation.

class MyFactory{
void createModel(){
   getState(ModelState.class).createModel();
}
}

if I’m creating a model when the modelstate is terminating (for example, the level is finished) I get NullPointerEx
So I’d like something like

if (getState(ModelState.class).isDetached())
     return;

But of course testing null will do as well

Why are you creating a model when the state is terminating?

And just a word on these two approaches and why the null check is better.

In the isDetached() case… isDetached() could lie. It leaves it up to the state to say whether it is attached or not and it could be buggy, wrong, etc… any number of reasons isDetached() could return true when it’s detached or false when it’s attached.

But what can never lie is getState() == null. By definition of what “attached” means.

It would be the equivalent of asking an item in an ArrayList if it’s still in the list.

2 Likes