AppState: best practises?

Hi there,

I’m a total noob using JME3+Lemur implementing some spare time project. (Typical 1st-person space flight stuff). I just implemented a few AbstractAppState-based states and I wondered:

  1. why some com.jme3.app.state.*State-implementations do not detach their nodes/scenes in their cleanup-implementation (like e.g. ChaseCameraAppState), and also re-attach them in their initialize() over and over again: maybe they are relying to some side-effect of re-attaching I don’t yet know?
  2. there are quite a lot of AppState-implementations out there which use some “if (someMember == null) { /* initMember */ }”-orgy in their initialize-implementation, which seem a bit odd to me. Before re-inventing the wheel: are there any “lifecycle-extensions” made to AbstractAppState a noob could use in order to have “setUpOnce()” (invoked by render thread) and “tearDownOnce()” (invoked in render thread) in order to not create such initMember-orgies?

What is considered convention / best practise regarding 1+2 by the community?

Thanks for helping me understanding!

Regarding 1:
It might be that it’s simply easier to leave that stuff out. Those AppStates might be designed to only be removed upon application stop. MANY people just skip their cleanup. It’s a habit which the GC trains you :stuck_out_tongue:

Regarding 2:
That’s the only really reliable way to be on the mainthread, in update().
Things like setEnabled shouldn’t but could be called from outside the main thread.
stateAttached should be fine, though.

Also this might be in order to re-use those variables when the state is re-attached (imagine detaching, attaching, d, a, d, a…): If you would create everything in stateAttached, you would always recreate it.

If you have some more practical examples someone might help you even better.

1 Like

Regarding ChaseCam not cleaning up properly, I already noticed that some time ago and made a thread about it. I’m planning on fixing it and making a PR but I never get to that…

Thank you for your explanations… yeah, I know that GC-thoughtlessness (a lot), when I started coding some decades ago we spent nights looking for resource-leaks (C+ASM) killing our long-running applications, and I’m still pretty aware of such “strings attached”-topics…

API seems a bit odd sometimes… like “I wonder why AppState::initialize was defined to take Application and AppStateManager as a parameter, can the AppStateManager, used for “initialize”-invocation differ from the one given by Application::getAppStateManager?.. hmm, no, the default Application-implementations seem to have a quasi-immutable “stateManager”-class member anyways, which cannot intentionally be changed”. Strange… why not hide that implementation detail if not a relevant use case and pass Application-instance as only argument?

Don’t get me wrong, I really like JME3, as it seem to offer a lot of convenience for implementing stuff fast, just trying to get my head around the API design… ATM I replace my SimpleApplication-specific implementation details by “the way it’s meant to be used without being Simple-helpers”. And ATM i wonder why there is a handy “RootNodeAppState” but a handy “GuiNodeAppState” seem to be absent - don’t know why… hope you guys are patient with some old dude asking strange or pedantic questions every now and then…

Okay, so I’ve just decided to use RootNodeAppState as my default implementation pattern, realizing my most implementation details using it as a pattern.

And thanks for explanation regarding the “setEnabled” I already wondered why most just seem to flip Culling settings in it instead of attaching/detaching nodes. I will try to use “enabled” for my state transition between menu/pause- and flight-states, maybe that reduces the time the transition takes, which seem to take pretty long for me, maybe because of the attachState/detachState-usage…

Some of the old JME app states are pretty bad examples to follow. If they aren’t extending BaseAppState then they are probably half-broken. BaseAppState should be the base class you use as there are nicer life cycle methods to override. (As to why app state manager is passed in the AppState interface it’s because many many many app states will want to lookup sibling app states and it saves them a call… BaseAppState’s initialize only passes Application because it’s already grabbed the state manager and provides convenient getState() methods already locally.)

If you want to see good examples of app state use then you can look at any of the many examples I have out there… whether the half-dozen AppStates in Lemur or in any of my sample apps.

For example, some recent sample apps:

Some older more complicated apps:

All of which heavily use app states.

1 Like

…because for what they do, they would be identical. RootNodeAppState is not for “managing the root node of your APPLICATION” It’s for “managing the root node of a VIEWPORT”. So it can already be used to manage a ‘gui node’… just give it a root node that is in the gui bucket. Done.

Some of the old JME app states are pretty bad examples to follow […] you can look at any of the many examples I have out there… whether the half-dozen AppStates in Lemur or in any of my sample apps.
(Example Apps)

Very, very helpful, thanks a lot!