fix for issue #1178 (BulletAppState violates AppState contract) (#1187)

* fix for issue #1178 (BulletAppState violates AppState contract)

* BulletAppState: make isRunning volatile (potential multithreaded access)
fix-openal-soft-deadlink
Stephen Gold 5 years ago committed by GitHub
parent dcb66977ba
commit 0425c61dd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 96
      jme3-bullet/src/common/java/com/jme3/bullet/BulletAppState.java

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2018 jMonkeyEngine * Copyright (c) 2009-2019 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -32,7 +32,7 @@
package com.jme3.bullet; package com.jme3.bullet;
import com.jme3.app.Application; import com.jme3.app.Application;
import com.jme3.app.state.AppState; import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager; import com.jme3.app.state.AppStateManager;
import com.jme3.bullet.PhysicsSpace.BroadphaseType; import com.jme3.bullet.PhysicsSpace.BroadphaseType;
import com.jme3.bullet.debug.BulletDebugAppState; import com.jme3.bullet.debug.BulletDebugAppState;
@ -49,27 +49,16 @@ import java.util.logging.Logger;
* *
* @author normenhansen * @author normenhansen
*/ */
public class BulletAppState implements AppState, PhysicsTickListener { public class BulletAppState
extends AbstractAppState
// FIXME: the bullet app state doesn't follow the proper AppState implements PhysicsTickListener {
// 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 * true if-and-only-if the physics simulation is running (started but not
* yet stopped) * yet stopped)
*/ */
protected boolean initialized = false; protected volatile boolean isRunning = false;
protected Application app; protected Application app;
private String id;
/** /**
* manager that manages this state, set during attach * manager that manages this state, set during attach
*/ */
@ -245,7 +234,7 @@ public class BulletAppState implements AppState, PhysicsTickListener {
* sooner, invoke this method. * sooner, invoke this method.
*/ */
public void startPhysics() { public void startPhysics() {
if (initialized) { if (isRunning) {
return; return;
} }
@ -265,14 +254,14 @@ public class BulletAppState implements AppState, PhysicsTickListener {
throw new IllegalStateException(threadingType.toString()); throw new IllegalStateException(threadingType.toString());
} }
initialized = true; isRunning = true;
} }
/** /**
* Stop physics after this state is detached. * Stop physics after this state is detached.
*/ */
public void stopPhysics() { public void stopPhysics() {
if(!initialized){ if (!isRunning) {
return; return;
} }
if (executor != null) { if (executor != null) {
@ -281,7 +270,7 @@ public class BulletAppState implements AppState, PhysicsTickListener {
} }
pSpace.removeTickListener(this); pSpace.removeTickListener(this);
pSpace.destroy(); pSpace.destroy();
initialized = false; isRunning = false;
} }
/** /**
@ -291,54 +280,14 @@ public class BulletAppState implements AppState, PhysicsTickListener {
* @param stateManager the manager for this state (not null) * @param stateManager the manager for this state (not null)
* @param app the application which owns this state (not null) * @param app the application which owns this state (not null)
*/ */
@Override
public void initialize(AppStateManager stateManager, Application app) { public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
this.app = app; this.app = app;
this.stateManager = stateManager; this.stateManager = stateManager;
startPhysics(); startPhysics();
} }
/**
* Test whether the physics simulation is running (started but not yet
* stopped).
*
* @return true if running, otherwise false
*/
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;
}
/**
* Enable or disable this state.
*
* @param enabled true → enable, false → disable
*/
public void setEnabled(boolean enabled) {
this.active = enabled;
}
/**
* Test whether this state is enabled.
*
* @return true if enabled, otherwise false
*/
public boolean isEnabled() {
return active;
}
/** /**
* Alter whether debug visualization is enabled. * Alter whether debug visualization is enabled.
* *
@ -364,8 +313,10 @@ public class BulletAppState implements AppState, PhysicsTickListener {
* *
* @param stateManager (not null) * @param stateManager (not null)
*/ */
@Override
public void stateAttached(AppStateManager stateManager) { public void stateAttached(AppStateManager stateManager) {
if (!initialized) { super.stateAttached(stateManager);
if (!isRunning) {
startPhysics(); startPhysics();
} }
if (threadingType == ThreadingType.PARALLEL) { if (threadingType == ThreadingType.PARALLEL) {
@ -377,15 +328,6 @@ public class BulletAppState implements AppState, PhysicsTickListener {
} }
} }
/**
* Transition this state from running to terminating. Should be invoked only
* by a subclass or by the AppStateManager.
*
* @param stateManager (not null)
*/
public void stateDetached(AppStateManager stateManager) {
}
/** /**
* Update this state prior to rendering. Should be invoked only by a * Update this state prior to rendering. Should be invoked only by a
* subclass or by the AppStateManager. Invoked once per frame, provided the * subclass or by the AppStateManager. Invoked once per frame, provided the
@ -393,7 +335,9 @@ public class BulletAppState implements AppState, PhysicsTickListener {
* *
* @param tpf the time interval between frames (in seconds, ≥0) * @param tpf the time interval between frames (in seconds, ≥0)
*/ */
@Override
public void update(float tpf) { public void update(float tpf) {
super.update(tpf);
if (debugEnabled && debugAppState == null && pSpace != null) { if (debugEnabled && debugAppState == null && pSpace != null) {
debugAppState = new BulletDebugAppState(pSpace); debugAppState = new BulletDebugAppState(pSpace);
stateManager.attach(debugAppState); stateManager.attach(debugAppState);
@ -415,7 +359,9 @@ public class BulletAppState implements AppState, PhysicsTickListener {
* *
* @param rm the render manager (not null) * @param rm the render manager (not null)
*/ */
@Override
public void render(RenderManager rm) { public void render(RenderManager rm) {
super.render(rm);
if (!active) { if (!active) {
return; return;
} }
@ -432,7 +378,9 @@ public class BulletAppState implements AppState, PhysicsTickListener {
* invoked only by a subclass or by the AppStateManager. Invoked once per * invoked only by a subclass or by the AppStateManager. Invoked once per
* frame, provided the state is attached and enabled. * frame, provided the state is attached and enabled.
*/ */
@Override
public void postRender() { public void postRender() {
super.postRender();
if (physicsFuture != null) { if (physicsFuture != null) {
try { try {
physicsFuture.get(); physicsFuture.get();
@ -451,12 +399,14 @@ public class BulletAppState implements AppState, PhysicsTickListener {
* {@link #initialize(com.jme3.app.state.AppStateManager, com.jme3.app.Application)} * {@link #initialize(com.jme3.app.state.AppStateManager, com.jme3.app.Application)}
* is invoked. * is invoked.
*/ */
@Override
public void cleanup() { public void cleanup() {
if (debugAppState != null) { if (debugAppState != null) {
stateManager.detach(debugAppState); stateManager.detach(debugAppState);
debugAppState = null; debugAppState = null;
} }
stopPhysics(); stopPhysics();
super.cleanup();
} }
/** /**

Loading…
Cancel
Save