Composite AppState

Hi Guys,
Lookin at the AppState interface, I wonder if anyone ever thought of creating a composite version of AppState?

It should be something like that:

abstract CompositeAppState

  • Inherits from BaseAppState
  • will have a private childStates collection
  • will have CRUD methods for adding/deleting/getting child states
  • some of the methods especially intialize/cleanup/render/update will also delegate to the corresponding methods in the child states
  • some of the methods will return the accumulated recursive return value of the same child states mehtods
  • State manger needs to be aware only of root (non child) states

I think this pattern will allow easier state management for applications using a lot of (or complex) app states.
I wonder what are the equivalents of AppState in Unity/Unreal/Godot and do they use the composite pattern.

What do you think?
If the community agrees on the necessity of such class, I will try to write the initial version.

Cheers!

1 Like

I use it all the time:

3 Likes

I had a similar idea to this; where each main stage of the game (main level, customisation, briefing etc) has a coordinating app state that adds child app states and when it is removed it automatically removes its children. It doesn’t go quite as far as you’re suggesting (totally replacing the StateManager) it just handles removals automatically. It’s pretty easy to roll your own though if this is the way you want to organise things

public abstract class CompositeAppState extends BaseAppState{

    List<AppState> childStates = new ArrayList<>();

    @Override
    protected void cleanup(Application app){
        for(AppState childState : childStates){
            getStateManager().detach(childState);
        }
    }
    /**
     * Attaches a state that is implicitly a child of this state. Meaning when this state gets removed so do the
     * child states
     */
    protected void attachChildState(AppState state){
        getStateManager().attach(state);
        childStates.add(state);
    }

    public void detachChildState(ShipCustomisationRunnerState shipCustomisationRunnerState){
        getStateManager().detach(shipCustomisationRunnerState);
        childStates.remove(shipCustomisationRunnerState);
    }
}
1 Like

Note: if you aren’t already using SiO2 then I highly recommend taking a look at it… even if you only borrow a few classes, there are a lot of useful utilities in there.

2 Likes

Cool! (I’ll take a look at SiO2)
Looking at your implementation - Is it mandatory in JME for each and every app state to be attached to the AppStateManager?
Can’t I just attach / detach the root app states and still be able to delegate calls to the child states?

Yeah… cool. both your and Paul’s implementations are registering (attach / detach) the child app states with the AppStateManager. Is this registration mandatory?

No, but it makes the threading life cycle a lot clearer. It’s also more future proof for whatever JME adds in the future.

…and most importantly of all, it means that any other BaseAppState that calls getState() can find your child states.

Edit: note that there are a dozen or so similar hard-lessons-learned in SiO2’s composite app state. Ask me about any feature and I probably have a story. :slight_smile:

3 Likes

Its amazing how similar mine and pspeed’s approachs are. Convergent evolution!

That said, pspeed’s is clearly better, I might start using that

1 Like

You wouldn’t want to rewrite what the state manager do anyway, and if for some reasons there will be revolutionary or breaking changes in the state manager, they will be reflected in this feature without replicating changes.

EDIT:

If I would work on this feature, I will be more inclined to just create an AppState out of the StateManager itself, so envision the possiblity of subclassing the AppStateManager instead of replicating the activities of the state manager:

public class CompositeAppState extends AppStateManager implements AppState {
     ...
}

But, for some people, it might produce a weird relationship of having a statemanager under a statemanager, in my case, it is very logical sense to not repeat APIs… though I haven’t studied this possibility yet.

EDIT2:
If you don’t want to create this cyclic relationship, then you might consider compositing another state-manager under this CompositeState (EDIT: this is same of the discussion made here getStateManager()), there are a lot of approaches at this stage, you must select the most reliable and adaptable one for sure, in addition to monitoring the thread-safety of the attach/detach/update.

I feel like the question was answered appropriately without providing even crazier ideas.

Not too many game devs answered the main question in this thread - does JME needs to have a CompositeAppState. @pspeed & @richtea did create such component. I’m not sure about @Pavl_G
I believe that any serious game dev. which needs to handle significant changing situations in his game will benefit from such a component and therefore I think JME should provide it out of the box as part of its engine - core package.
My initial thought was that child states doesn’t need to have any direct relation with the state manager but I don’t understand about JME’s rendering and certainly not going to argue with years of experience and insights of other devs so I think that Paul’s solution is a good approach and we should adopt it.
Question is to Paul - can we copy your CompositeAppState (hopefully it doesn’t have significant dependencies) to JME core ? if not, then I will create one based on Paul’s approach.

Cheers! :slight_smile:

My personal answer would be “No, because if you aren’t already using SiO2 then you are doing development in ‘hard mode’.” But I admit that’s a biased point of view. (There are a lot of things in SiO2 that JME suffers for not having already.)

It’s fine if you wan to copy it. I don’t think it has any other dependencies.

And it’s probably not a class that suffers from having 2 year update cycles.

There are a handful of classes in SiO2 that I feel like every (normal) game should be using… but I think of SiO2 like Guava… just something you always use with the core stuff.

1 Like

Thanks a lot! I will do that

I don’t view it as essential, though the way I use app states it’s not something that has come up. I have no objections to that being in core if others view it as useful.

2 Likes

I also find jme-core would benefit from @pspeed CompositeAppState class.
Having it in jme-core may also improve its visibility and the related best practices.
A quick note about it in the wiki would be nice.

1 Like

Good news - Paul’s CompositeAppState was integrated into JME’s engine core and will be available for us to use in v3.7 :ok_hand:

8 Likes