[SOLVED] On IllegalStateException: Scene graph is not properly updated for rendering and Future/Call

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.

[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.

1 Like

Thanks pspeed this was exactly what I needed. Now it works perfectly (at least it seems to :smiley: ). 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. :slight_smile: