Hi, i have a really frustrating problem
I have a client that should react to events and add objects to the gameworld.
Here is the code for the Gamestate (the important part is BOLD)
package de.mbws.client.state;
import java.util.HashMap;
import com.jme.app.StandardGameState;
import com.jme.bounding.BoundingBox;
import com.jme.input.ChaseCamera;
import com.jme.input.InputHandler;
import com.jme.input.MouseInput;
import com.jme.input.thirdperson.ThirdPersonMouseLook;
import com.jme.light.DirectionalLight;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Node;
import com.jme.scene.Skybox;
import com.jme.scene.shape.Box;
import com.jme.scene.state.LightState;
import com.jme.system.DisplaySystem;
import de.mbws.client.data.ClientPlayerData;
import de.mbws.client.data.ObjectNode;
import de.mbws.client.state.handler.TestGameHandler;
import de.mbws.common.eventdata.generated.WorldObject;
public class TestGameState extends StandardGameState {
private Node player;
Node player2;
// private ChaseCamera chaser;
protected InputHandler input;
protected DisplaySystem display;
protected Skybox skybox;
// The chase camera, this will follow our player as he zooms around the
// level
private ChaseCamera chaser;
public volatile boolean add = false;
public volatile int i = 0;
public TestGameState(String name) {
super(name);
this.display = DisplaySystem.getDisplaySystem();
// Light the world
buildLighting();
// Build the player
buildPlayer();
// build the chase cam
buildChaseCamera();
// build the player input
buildInput();
// addPlayer();
// just for testing we added some box as secondary player
// addPlayer();
// update the scene graph for rendering
rootNode.updateGeometricState(0.0f, true);
rootNode.updateRenderState();
TestThread t = new TestThread();
t.start();
}
private void buildInput() {
input = new TestGameHandler(player, null);
}
/**
* we are going to build the player object here. For now, we will use a box
* as a place holder. This is a good demonstration that you don't always
* need your graphics in place before you can start working on your
* application.
*
*/
private void buildPlayer() {
// box stand in
Box b = new Box("box", new Vector3f(), 0.35f, 0.25f, 0.5f);
b.setModelBound(new BoundingBox());
b.updateModelBound();
player = new Node("Player Node");
// player.setLocalTranslation(new Vector3f(100, 0, 100));
Vector3f location = new Vector3f(ClientPlayerData.getInstance()
.getCharacterData().getCharacterStatus().getCoordinateX(),
ClientPlayerData.getInstance().getCharacterData()
.getCharacterStatus().getCoordinateY(),
ClientPlayerData.getInstance().getCharacterData()
.getCharacterStatus().getCoordinateZ());
player.setLocalTranslation(location);
rootNode.attachChild(player);
player.attachChild(b);
player.updateWorldBound();
}
public void updatePlayer() {
Vector3f location = new Vector3f(ClientPlayerData.getInstance()
.getCharacterData().getCharacterStatus().getCoordinateX(),
ClientPlayerData.getInstance().getCharacterData()
.getCharacterStatus().getCoordinateY(),
ClientPlayerData.getInstance().getCharacterData()
.getCharacterStatus().getCoordinateZ());
player.setLocalTranslation(location);
}
// TODO REMOVE BELOW
public void addPlayer() {
// box stand in
Box b = new Box("box", new Vector3f(), 0.35f, 0.5f, 0.25f);
b.setDefaultColor(new ColorRGBA(ColorRGBA.white));
b.setModelBound(new BoundingBox());
b.updateModelBound();
player2 = new Node("Player2 Node");
player2.setLocalTranslation(new Vector3f(100, 0, 100));
rootNode.attachChild(player2);
player2.attachChild(b);
player2.updateWorldBound();
}
public void movePlayer(Vector3f newLocation) {
player2.setLocalTranslation(newLocation);
} // TODO: REMOVE ABOVE
/**
* creates a light for the terrain.
*/
private void buildLighting() {
/** Set up a basic, default light. */
DirectionalLight light = new DirectionalLight();
light.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
light.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));
light.setDirection(new Vector3f(1, -1, 0));
light.setEnabled(true);
/** Attach the light to a lightState and the lightState to rootNode. */
LightState lightState = display.getRenderer().createLightState();
lightState.setEnabled(true);
lightState.attach(light);
rootNode.setRenderState(lightState);
}
/**
* set the basic parameters of the chase camera. This includes the offset.
* We want to be behind the vehicle and a little above it. So we will the
* offset as 0 for x and z, but be 1.5 times higher than the node.
*
* We then set the roll out parameters (2 units is the closest the camera
* can get, and 5 is the furthest).
*
*/
private void buildChaseCamera() {
Vector3f targetOffset = new Vector3f();
targetOffset.y = ((BoundingBox) player.getWorldBound()).yExtent * 1.5f;
HashMap props = new HashMap();
props.put(ThirdPersonMouseLook.PROP_MAXROLLOUT, "40");
props.put(ThirdPersonMouseLook.PROP_MINROLLOUT, "3");
props.put(ChaseCamera.PROP_TARGETOFFSET, targetOffset);
chaser = new ChaseCamera(cam, player, props);
chaser.setActionSpeed(100f);
}
/**
* This is where derived classes are supposed to put their game logic. Gets
* called between the input.update and rootNode.updateGeometricState calls.
*
* <p>
* Much like the structure of <code>SimpleGame</code>.
* </p>
*
* @param tpf
* The time since the last frame.
*/
protected void stateUpdate(float tpf) {
// update the keyboard input (move the player around)
input.update(tpf);
// update the chase camera to handle the player moving around.
chaser.update(tpf);
float camMinHeightPlayer = player.getWorldTranslation().y + 2f;
cam.getLocation().y = camMinHeightPlayer;
cam.update();
if (add) {
addPlayer();
add = false;
}
rootNode.updateGeometricState(tpf, true);
}
/**
* This is where derived classes are supposed to put their render logic.
* Gets called before the rootNode gets rendered.
*
* <p>
* Much like the structure of <code>SimpleGame</code>.
* </p>
*
* @param tpf
* The time since the last frame.
*/
protected void stateRender(float tpf) {
display.getRenderer().clearBuffers();
super.stateRender(tpf);
}
/**
* @see com.jme.app.StandardGameState#onActivate()
*/
public void onActivate() {
display.setTitle("Test Game State System - Game State");
// TODO: SUCK MY DICK WHAT A HECK OF A BUG !!!! Take that out
// later when all works with a correct mouse
MouseInput.get().setCursorVisible(false);
super.onActivate();
}
public ObjectNode addObject(WorldObject objectInfo) {
Box b = new Box("box2", new Vector3f(), 0.35f, 0.25f, 0.5f);
b.setDefaultColor(new ColorRGBA(ColorRGBA.white));
b.setModelBound(new BoundingBox());
b.updateModelBound();
ObjectNode n = new ObjectNode("test");// +objectInfo.getObjectID());
// IntVector3D l = objectInfo.getLocation();
Vector3f location = new Vector3f(new Vector3f(100, 0, 100));// l.getX(),l.getY(),l.getZ());
n.setLocalTranslation(location);
// IntVector3D h = objectInfo.getHeading();
// Vector3f rotation = new Vector3f(h.getX(),h.getY(),h.getZ());
// n.setLocalTranslation(rotation);
rootNode.attachChild(n);
n.attachChild(b);
n.updateWorldBound();
rootNode.updateGeometricState(0.0f, true);
rootNode.updateRenderState();
// display.getRenderer().clearBuffers();
// display.getRenderer().draw(rootNode);
return n;
}
public void deleteObject(ObjectNode node) {
rootNode.detachChild(node);
}
class TestThread extends Thread {
int count = 0;
public void run() {
try {
while (add != true) {
Thread.sleep(20);
count++;
if (count == 1000) {
add = true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
As you can see i use an internal threadclass to set a boolean variable. If that is true a new box is inserted into the scene.
This works !!
Now if i take that threadclass and put it in another thread (an eventlistener used for networkevents triggering such a spawning) then strange things happen.
Here the modified code of the threadclass:
class TestThread extends Thread {
int count = 0;
public void run() {
try {
boolean add = false;
while (add != true) {
Thread.sleep(20);
TestGameState gameState = (TestGameState) GameStateManager
.getInstance().getChild("game");
count++;
if (count == 1000) {
gameState.add = true;
add = true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Now what happens is the following:
in BOTH cases add is set to true and in BOTH cases addPlayer gets called by the stateUpdate method in TestGameState.
In BOTH cases the debug messages tell me that the second box was added.
But in the second case the box NEVER appears on the screen !!!
I simply have arrived at the point where i cant seem to see any further hint at what the problem could be :(
Any help appreciated.