Hi all,
first of all let me say thank you for the effort in developing the jMonkey Engine. I’m really enjoying programming with it, thank you guys. As the title says I’m having some problems with the scene graph. As far as I understand, reading other similar topics, the problem arise because I’m trying to modify the scene graph from outside the rendering thread. This perfectly make sense to me. What it is not clear is how exactly resolve this problem with the Future/Callable code snippet. I’m setting up a client/server (let’s call it) “game”. The Main class has a listener for Client (that manage the connection) events. In my case when the Client receives the message from Server that a new player has joined the game, it fires an event and the listener (that is a Main object variable), manage it.
Here’s the code of the Main method that join an already existing match and add just this player geometry:
pre type="java"
private void joinLANMatch() {
// Start client
initClient(false);
// key mapping
initKeys();
// Inintialize physics
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
// Load level
createBasicLevel();
// create a new player
p = new Player(“Nibbler”);
p.setId(client.clientGameConnection.requestUniqueEntityId());
// Create character and attach it to the player
c = new CharacterOne(assetManager, p);
// attach the character to the client
client.setCharacter©;
// Attach the character to the physic simulation and the scene graph
rootNode.attachChild(c.getSpatial());
bulletAppState.getPhysicsSpace().add(c.getPhysicsControl());
}/pre
And here there is the code of the listener object (inside the same Main class) that add a new player. The problem is that this code is executed on a different thread:
pre type="java"
private GameClientListener gameClientListener = new GameClientListener() {
if (e.object instanceof JoinUpdate) {
JoinUpdate ju = (JoinUpdate) e.object;
for (final NewPlayerUpdate other : ju.otherPlayers) {
Player newP = new Player(other.getPlayerName());
newP.setId(other.getId());
// Create character and attach it to the player
Character newC = null;
switch (other.getCharacterClass()) {
case Character.CHARACTER_ONE:
newC = new CharacterOne(assetManager, newP);
}
// TODO: multithread problems
rootNode.attachChild(newC.getSpatial());
bulletAppState.getPhysicsSpace().add(newC.getPhysicsControl());
// Add the new player to the list
playersEntities.put(newC.getId(), newC);
}
}
}/pre
So, my problem is that I don’t really understand how to resolve this problem using the following suggested snippet code:
[snippet id=“10”]
Thanks to all in advance for any hints.
[SOLVED] On IllegalStateException: Scene graph is not properly updated for rendering and Future/Call
[java]
class AttachToParent implements Callable {
Node parent;
Spatial child;
public AttachToParent( Node parent, Spatial child ) {
this.parent = parent;
this.child = child;
}
public Object call() {
parent.attachChild(child);
return null;
}
}
[/java]
then instead of calling rootNode.attachChild() on the other thread, call application.enqueue( new AttachToParent(rootNode, child) ).
…and never under any circumstances use future.get(). Just leave it a lone.
Thanks pspeed this was exactly what I needed. Now it works perfectly (at least it seems to ). Now I guess I should do something similar also for updating geometries positions, right? And should I do something similar also for attaching the Control to the Physics State?
Thanks again a lot for the quick and really useful reply.
I actually don’t know if any of that is thread safe or not. Also maybe it can be made less granular on your end to require fewer tiny Callables in favor of some larger ones.
I don’t do it this way but may way is a lot harder to explain.