AbstractAppState::initialize vs AbstractAppState::stateAttached

I am adding rootNode and gui node to Application::ViewPort & Application::guiViewPort respectively.



When exactly I should use AbstractAppState::initialize and AbstractAppState::stateAttached for this attachment?What’s the difference?



For this particular code it wont matter much, I was asking for the bigger picture.

stateAttached() → called as soon as the state is attached… like before the attach() call even returns. I haven’t found a great use for this but it’s bound to be useful sometime. It is called on the same thread that you called attach() on.



initialize() → called during the update loop the first time the state is encountered after being attached. Actually, it’s called every time if isInitialized() returns false.



The state management of a state (pun intended) is actually a little tricky if you plan to enabled/disable them many times. Otherwise, do all of your initialization in initialize().



If you do plan to leave one attached and enable/disable it several times then I can go into more detail about that.

It is called on the same thread that you called attach()

I don't understand.

it’s called every time if isInitialized() returns false.

Does it mean, it might be called several times for one initialization?

If you do plan to leave one attached and enable/disable it several times then I can go into more detail about that.

Yes please!I would love to hear it in details. :)
iamcreasy said:
I don't understand.


You can attach app states from any thread. For example, you can even attach an app state from the main() method... in which case stateAttached() is called on that thread. initialize() is _always_ called on the render thread, ie: safe to modify the scene graph.

iamcreasy said:
Does it mean, it might be called several times for one initialization?


If you do not set initialized to true (for example if you forget to call super.initialize()) then your initialize method will be called over and over and over and over. There was a better way for JME to do this but this is the design we have. And it's not so bad as long as initialize() doesn't get messed up.

iamcreasy said:
Yes please! :)


AppStates essentially have a few states that we care about:
-attached/detached
-enabled/distabled
-initialized/not initialized (one of the side effects of the way initialize() calling was designed is that there is no way to support a guaranteed in-render thread terminate())

In my case, I really want the bulk of my "show this" and "unshow this" logic to happen as a combination of attached and enabled. Consequently, I have a base class with separate enable() and disable() methods.

So I have code in my base class like:
[java]
// the initialize my subclasses will actually use. This is where I might load
// assets that I want to preload that will be around for the entire life of the state
protected abstract void initialize( Application app );

// This is where I add things to my scene, rootNode, guiNode, whatever...
// it's called only when the state is attached, initialized, _and_ enabled.
protected abstract void enable();

// This is where I remove the things I did in enable(). This is called whenever
// the state is disabled _or_ detached. isEnabled() may still return true when
// this is called... for example, when the state is detached.
protected abstract void disable();

// Final to avoid subclasses messing it up. :)
@Override
public final void initialize( AppStateManager stateManager, Application app )
{
super.initialize( stateManager, app );

this.stateManager = stateManager;
this.app = app;
initialize( app );

if( isEnabled() )
enable();
}

@Override
public void setEnabled( boolean enabled )
{
if( isEnabled() == enabled )
return;
super.setEnabled(enabled);

if( enabled && getStateManager() != null )
enable();
else if( !enabled && getStateManager() != null )
disable();
}

@Override
public void stateDetached( AppStateManager stateManager )
{
if( isEnabled() )
disable();
super.stateDetached(stateManager);
this.stateManager = null;
}

[/java]

...or something like that. My base class does some more unrelated things so I tried to weed out the irrelevant bits.
2 Likes

Funny thing is that I actually committed a large fix to the AppState system before to do exactly what Paul mentioned in his post … But then it got some people mad (Normen …) due to it breaking backwards compat or whatnot and I had to revert it back.



Essentially what you would do with Paul’s code, is put it into its own abstract class like “AppService” and then have all your AppStates extend it. The principle is still the same, except that with this new class you generally can make less mistakes.

Maybe we could add a SimpleAppState to do it that then no one extend because they aren’t “simple”. :slight_smile:



I’m actually half glad I had to do this manually as in my case I inject some code into setEnabled() in a way that I wouldn’t have been able to do just be overriding it. My own base class is actually observable so that other things can watch its isEnabled() state… and it’s important that the listeners are called before enable() or disable().

pspeed said:
-initialized/not initialized (one of the side effects of the way initialize() calling was designed is that there is no way to support a guaranteed in-render thread terminate())

Can you please explain this to me. I am always trying to dig out how the whole system works.

// This is where I remove the things I did in enable(). This is called whenever
// the state is disabled _or_ detached. isEnabled() may still return true when
// this is called... for example, when the state is detached.


@pspeed Why it would return true when you have already called the disable function? (I am assuming once disable() is called all the children has been detached from their parent.) What's the benefit of returning true when those rootNode and guiNode doesn't hold anything.


pspeed said:
My own base class is actually observable so that other things can watch its isEnabled() state... and it's important that the listeners are called before enable() or disable().


observable...listeners are called before...would you please clarify. I am intrigued. :)
Momoko_Fan said:
Funny thing is that I actually committed a large fix to the AppState system before to do exactly what Paul mentioned in his post .. But then it got some people mad (Normen ...) due to it breaking backwards compat or whatnot and I had to revert it back.


Did it mess with the Bullet State?

This improvement looks mandatory.

The change doesn’t give you a chance to get in between, it would make AppStates a one-trick-pony. Now you can do everything.

@normen Can you give us an example, what can be done and what couldn’t been done?

No, find out yourself ^^ Maybe you should first try and grasp the concept of AppStates before you look at how it could be changed. Momoko_Fans memory on this seems to be blurry xD

:slight_smile: okey, I like the hard way.



One more question, does a normal(real life) scene should have one BulletAppState and one PhysicSpace inside it. right?

In real life? Let me look around… Nope, no BulletAppState in my room :wink:

A BulletAppState is just a class that steps the physics space inside of it using the update() callback of AppState basically. You could also put the code of the BulletAppState in the main application class instead. With AppStates you can have multiple physics spaces easily though.

1 Like
iamcreasy said:
Can you please explain this to me. I am always trying to dig out how the whole system works.


I can explain it but probably not in a way that's understandable. :) initialize() is always called on the render thread... even if you attach the state from another thread. There is no way to detach a state from another thread and have a "terminate()" method run on the render thread. stateDetached() is always run on the thread that detached the state... and if that's not the render thread then you won't be able to manipulate the scene graph at all. The net result is that you cannot detach a state from another thread. Fortunately, it comes up less often.

iamcreasy said:
@pspeed Why it would return true when you have already called the disable function? (I am assuming once disable() is called all the children has been detached from their parent.) What's the benefit of returning true when those rootNode and guiNode doesn't hold anything.


Because the app state isn't disabled in the setEnabled(false) sense. It's effectively disabled because it has been detached. If you attach it again then it is enabled again... an enable() would be called. This is different than if you setEnabled(false) and then detach it. Reattaching that app state would not call enable() because the state is disabled.

enable()/disable() are a way to properly initialize and clean up the app scene-related app state stuff no matter how the state gets to a "full enabled" situation. I couldn't think of better names for them... perhaps "realized" and "unrealized". (shrug)

iamcreasy said:
observable...listeners are called before...would you please clarify. I am intrigued. :)


My app states are all observable in that listeners can register to be notified when they become enabled and disabled. I use this for a few things but the most important was the StateGroup state. This keeps track of state children and makes sure that no more than one is enabled at a time. Useful when your states represent different pop-ups that cannot be on screen at the same time. So in Mythruna if you have the builder open and hit 'm' the fact that the map becomes enabled causes the builder state to become disabled (setEnabled(false)).
1 Like
normen said:
The change doesn't give you a chance to get in between, it would make AppStates a one-trick-pony. Now you can do everything.


That may have been true of momoko's changes but mine are actually fully backwards compatible with any subclasses. I still don't recommend making the change to AbstractAppState but it might be nice to have a slightly more feature rich subclass of AbstractAppState.

Yep, your changes could fit w/o problems into the AbstractAppState… Though it might break some stuff for people here and there I guess… Thats probably the danger in creating Abstract Classes for Interfaces :wink:

normen said:
Yep, your changes could fit w/o problems into the AbstractAppState.. Though it might break some stuff for people here and there I guess.. Thats probably the danger in creating Abstract Classes for Interfaces ;)


Nah, the app state works exactly the same if they've overridden methods. The only risk is that if they've overridden some methods then they don't get the new benefits.

Abstract implementations of interfaces are a good thing. They allow you to potentially add new methods to the interface without breaking existing code... but that also means they should be a minimal implementation if possible. Which is why I don't recommend changing it. However, a SimpleApplication equivalent of AbstractAppState might be appropriate. We could even name is SimpleAppState thereby making sure no one ever actually uses it. ;) ;) ;)

Right. Lets just wait and see whats actually becoming boilerplate in most projects, then add these…

Back to the thread topic, I found I should modify the screen graph in the AbstractAppState::Initialize() method I get the following error,



[java]Make sure scene graph state was not changed after

rootNode.updateGeometricState() call.

Problem spatial name: Root Node[/java]



To avoid this I have to put my code in AbstractAppState::stateAttached.



So, here goes the difference.

Then something else is wrong or you are calling initialize yourself somewhere.



Usually it’s the other way around and statchAttached() is the dangerous one since that can be run from a non-render thread. initialize() is always run from the render thread and always run in such a way that updates to the scene graph are allowed. I literally do it all the time.