* fix for issue #1178 (BulletAppState violates AppState contract) * BulletAppState: make isRunning volatile (potential multithreaded access)
This commit is contained in:
parent
dcb66977ba
commit
0425c61dd4
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2018 jMonkeyEngine
|
||||
* Copyright (c) 2009-2019 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -32,7 +32,7 @@
|
||||
package com.jme3.bullet;
|
||||
|
||||
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.bullet.PhysicsSpace.BroadphaseType;
|
||||
import com.jme3.bullet.debug.BulletDebugAppState;
|
||||
@ -49,27 +49,16 @@ import java.util.logging.Logger;
|
||||
*
|
||||
* @author normenhansen
|
||||
*/
|
||||
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
|
||||
public class BulletAppState
|
||||
extends AbstractAppState
|
||||
implements PhysicsTickListener {
|
||||
|
||||
/**
|
||||
* true if-and-only-if the physics simulation is running (started but not
|
||||
* yet stopped)
|
||||
*/
|
||||
protected boolean initialized = false;
|
||||
protected volatile boolean isRunning = false;
|
||||
protected Application app;
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* manager that manages this state, set during attach
|
||||
*/
|
||||
@ -245,7 +234,7 @@ public class BulletAppState implements AppState, PhysicsTickListener {
|
||||
* sooner, invoke this method.
|
||||
*/
|
||||
public void startPhysics() {
|
||||
if (initialized) {
|
||||
if (isRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -265,14 +254,14 @@ public class BulletAppState implements AppState, PhysicsTickListener {
|
||||
throw new IllegalStateException(threadingType.toString());
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
isRunning = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop physics after this state is detached.
|
||||
*/
|
||||
public void stopPhysics() {
|
||||
if(!initialized){
|
||||
if (!isRunning) {
|
||||
return;
|
||||
}
|
||||
if (executor != null) {
|
||||
@ -281,7 +270,7 @@ public class BulletAppState implements AppState, PhysicsTickListener {
|
||||
}
|
||||
pSpace.removeTickListener(this);
|
||||
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 app the application which owns this state (not null)
|
||||
*/
|
||||
@Override
|
||||
public void initialize(AppStateManager stateManager, Application app) {
|
||||
super.initialize(stateManager, app);
|
||||
this.app = app;
|
||||
this.stateManager = stateManager;
|
||||
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.
|
||||
*
|
||||
@ -364,8 +313,10 @@ public class BulletAppState implements AppState, PhysicsTickListener {
|
||||
*
|
||||
* @param stateManager (not null)
|
||||
*/
|
||||
@Override
|
||||
public void stateAttached(AppStateManager stateManager) {
|
||||
if (!initialized) {
|
||||
super.stateAttached(stateManager);
|
||||
if (!isRunning) {
|
||||
startPhysics();
|
||||
}
|
||||
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
|
||||
* 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)
|
||||
*/
|
||||
@Override
|
||||
public void update(float tpf) {
|
||||
super.update(tpf);
|
||||
if (debugEnabled && debugAppState == null && pSpace != null) {
|
||||
debugAppState = new BulletDebugAppState(pSpace);
|
||||
stateManager.attach(debugAppState);
|
||||
@ -415,7 +359,9 @@ public class BulletAppState implements AppState, PhysicsTickListener {
|
||||
*
|
||||
* @param rm the render manager (not null)
|
||||
*/
|
||||
@Override
|
||||
public void render(RenderManager rm) {
|
||||
super.render(rm);
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
@ -432,7 +378,9 @@ public class BulletAppState implements AppState, PhysicsTickListener {
|
||||
* invoked only by a subclass or by the AppStateManager. Invoked once per
|
||||
* frame, provided the state is attached and enabled.
|
||||
*/
|
||||
@Override
|
||||
public void postRender() {
|
||||
super.postRender();
|
||||
if (physicsFuture != null) {
|
||||
try {
|
||||
physicsFuture.get();
|
||||
@ -451,12 +399,14 @@ public class BulletAppState implements AppState, PhysicsTickListener {
|
||||
* {@link #initialize(com.jme3.app.state.AppStateManager, com.jme3.app.Application)}
|
||||
* is invoked.
|
||||
*/
|
||||
@Override
|
||||
public void cleanup() {
|
||||
if (debugAppState != null) {
|
||||
stateManager.detach(debugAppState);
|
||||
debugAppState = null;
|
||||
}
|
||||
stopPhysics();
|
||||
super.cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user