diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/BulletAppState.java b/jme3-bullet/src/common/java/com/jme3/bullet/BulletAppState.java index 9fb5b85f1..07a6ff608 100644 --- a/jme3-bullet/src/common/java/com/jme3/bullet/BulletAppState.java +++ b/jme3-bullet/src/common/java/com/jme3/bullet/BulletAppState.java @@ -51,12 +51,25 @@ import java.util.logging.Logger; */ public class BulletAppState implements AppState, PhysicsTickListener { + // FIXME: the bullet app state doesn't follow the proper AppState + // contract as it messes with its initialized state independently + // of when initialize()/cleanup() is actually called. This means + // that it's quite likely that the state manager will think the + // app state is initialized when it, itself, doesn't. This is + // a good example of why extending the abstract app state classes + // is better than implementing app state directly. If it wants + // to support a separate stated/not-started concept then that's + // separate from initialized/not-initialized but way more refactoring + // than I want to think about today. -pspeed:2019-09-15 + /** * true if-and-only-if the physics simulation is running (started but not * yet stopped) */ protected boolean initialized = false; protected Application app; + private String id; + /** * manager that manages this state, set during attach */ @@ -294,6 +307,20 @@ public class BulletAppState implements AppState, PhysicsTickListener { return initialized; } + /** + * Sets the unique ID of this app state. Note: that setting + * this while an app state is attached to the state manager will + * have no effect on ID-based lookups. + */ + protected void setId( String id ) { + this.id = id; + } + + @Override + public String getId() { + return id; + } + /** * Enable or disable this state. * diff --git a/jme3-core/src/main/java/com/jme3/app/state/AbstractAppState.java b/jme3-core/src/main/java/com/jme3/app/state/AbstractAppState.java index c2e3642da..96b7e6b6c 100644 --- a/jme3-core/src/main/java/com/jme3/app/state/AbstractAppState.java +++ b/jme3-core/src/main/java/com/jme3/app/state/AbstractAppState.java @@ -40,7 +40,7 @@ import com.jme3.renderer.RenderManager; * @author Kirill Vainer * @see com.jme3.app.state.BaseAppState */ -public class AbstractAppState implements AppState { +public abstract class AbstractAppState implements AppState { /** * initialized is set to true when the method @@ -50,38 +50,70 @@ public class AbstractAppState implements AppState { */ protected boolean initialized = false; private boolean enabled = true; + private String id; + + protected AbstractAppState() { + } + + protected AbstractAppState( String id ) { + this.id = id; + } + @Override public void initialize(AppStateManager stateManager, Application app) { initialized = true; } + @Override public boolean isInitialized() { return initialized; } + /** + * Sets the unique ID of this app state. Note: that setting + * this while an app state is attached to the state manager will + * have no effect on ID-based lookups. + */ + protected void setId( String id ) { + this.id = id; + } + + @Override + public String getId() { + return id; + } + + @Override public void setEnabled(boolean enabled) { this.enabled = enabled; } + @Override public boolean isEnabled() { return enabled; } + @Override public void stateAttached(AppStateManager stateManager) { } + @Override public void stateDetached(AppStateManager stateManager) { } + @Override public void update(float tpf) { } + @Override public void render(RenderManager rm) { } + @Override public void postRender(){ } + @Override public void cleanup() { initialized = false; } diff --git a/jme3-core/src/main/java/com/jme3/app/state/AppState.java b/jme3-core/src/main/java/com/jme3/app/state/AppState.java index 72988c0ef..33a6d28d5 100644 --- a/jme3-core/src/main/java/com/jme3/app/state/AppState.java +++ b/jme3-core/src/main/java/com/jme3/app/state/AppState.java @@ -90,6 +90,12 @@ public interface AppState { */ public boolean isInitialized(); + /** + * Returns the unique ID for this AppState or null if it has no + * unique ID. + */ + public String getId(); + /** * Enable or disable the functionality of the AppState. * The effect of this call depends on implementation. An diff --git a/jme3-core/src/main/java/com/jme3/app/state/BaseAppState.java b/jme3-core/src/main/java/com/jme3/app/state/BaseAppState.java index cee045355..a74521561 100644 --- a/jme3-core/src/main/java/com/jme3/app/state/BaseAppState.java +++ b/jme3-core/src/main/java/com/jme3/app/state/BaseAppState.java @@ -78,6 +78,14 @@ public abstract class BaseAppState implements AppState { private Application app; private boolean initialized; private boolean enabled = true; + private String id; + + protected BaseAppState() { + } + + protected BaseAppState( String id ) { + this.id = id; + } /** * Called during initialization once the app state is @@ -133,6 +141,20 @@ public abstract class BaseAppState implements AppState { return initialized; } + /** + * Sets the unique ID of this app state. Note: that setting + * this while an app state is attached to the state manager will + * have no effect on ID-based lookups. + */ + protected void setId( String id ) { + this.id = id; + } + + @Override + public String getId() { + return id; + } + public final Application getApplication() { return app; } diff --git a/jme3-core/src/main/java/com/jme3/app/state/RootNodeAppState.java b/jme3-core/src/main/java/com/jme3/app/state/RootNodeAppState.java index 8daa9dc3a..f7406ba55 100644 --- a/jme3-core/src/main/java/com/jme3/app/state/RootNodeAppState.java +++ b/jme3-core/src/main/java/com/jme3/app/state/RootNodeAppState.java @@ -85,6 +85,18 @@ public class RootNodeAppState extends AbstractAppState { this.rootNode = rootNode; } + /** + * Creates the AppState with the given unique ID, ViewPort, and root Node, attaches + * the root Node to the ViewPort and updates it. + * @param viewPort An existing ViewPort + * @param rootNode An existing root Node + */ + public RootNodeAppState( String id, ViewPort viewPort, Node rootNode ) { + super(id); + this.viewPort = viewPort; + this.rootNode = rootNode; + } + @Override public void initialize(AppStateManager stateManager, Application app) { if (rootNode == null) { @@ -101,6 +113,12 @@ public class RootNodeAppState extends AbstractAppState { public void update(float tpf) { super.update(tpf); rootNode.updateLogicalState(tpf); + + // FIXME: I'm 99% sure that updateGeometricState() should be + // called in render() so that it is done as late as possible. + // In complicated app state setups, cross-state chatter could + // cause nodes (or their children) to be updated after this + // app state's update has been called. -pspeed:2019-09-15 rootNode.updateGeometricState(); } diff --git a/jme3-core/src/main/java/com/jme3/cinematic/Cinematic.java b/jme3-core/src/main/java/com/jme3/cinematic/Cinematic.java index d9e9d5b11..3bcbc17a7 100644 --- a/jme3-core/src/main/java/com/jme3/cinematic/Cinematic.java +++ b/jme3-core/src/main/java/com/jme3/cinematic/Cinematic.java @@ -99,6 +99,7 @@ public class Cinematic extends AbstractCinematicEvent implements AppState { private boolean initialized = false; private Map> eventsData; private float nextEnqueue = 0; + private String id; /** * Used for serialization creates a cinematic, don't use this constructor @@ -291,6 +292,20 @@ public class Cinematic extends AbstractCinematicEvent implements AppState { return initialized; } + /** + * Sets the unique ID of this app state. Note: that setting + * this while an app state is attached to the state manager will + * have no effect on ID-based lookups. + */ + protected void setId( String id ) { + this.id = id; + } + + @Override + public String getId() { + return id; + } + /** * passing true has the same effect as play() you should use play(), * pause(), stop() to handle the cinematic playing state.