Updating spatial through network

Hi all monkyes!!



I’m here to get other good advices on how to do something that I don’t know how top solve:



I’ve made a simple client-server architecture where clients’ characters are syncornized in a scene (town.zip) and all networking trouble are just done.

To be more precise and to help you finding the solution with me I will show how is implemented the architecture that do the syncrnonization:



The client is just a simple appwhere a scene is loaded and a character, made of a simple PhysicsCharacter, move through this in a physics context.

This is done in a really basic mode like the TestQ3 does because I’s really simple to implement something like this.

When the player does some movement a message is sent to others clients by the server, that broadcast it after updating the position on the players list, and the code that does this is shown below and is done in the update method:



Client send a message:

[java]

player.setWalkDirection(walkDirection.setY(0).multLocal(0.5f));

cam.setLocation(player.getPhysicsLocation());

if (up || down || left || right) {

client.send(new MovementMessage(walkDirection, -1, true));

}

[/java]



The server broadcast it after updating:

[java]

private void movementMessageReceived(final MovementMessage message, final HostedConnection source){

Integer id = source.getId();

message.setPlayerId(id);

playerManager.updatePlayer(id, message.getNewPosition());



server.broadcast(new Filters().notEqualTo(source), message);

Logger.getLogger(MainServer.class.getName()).log(Level.INFO, “Broadcasting MovementMessage from {0}”, id);;

}



// PlayerManager:

private HashMap<Integer, Vector3f> players;

public synchronized void updatePlayer(Integer id, Vector3f newPosition){

players.get(id).set(newPosition);

}

[/java]



And other clients receive the message

[java]

private void movementMessageReceived(MovementMessage message) {

Integer id = message.getPlayerId();

playerManager.movePlayer(id, message.getNewPosition());

Logger.getLogger(MainClient.class.getName()).log(Level.INFO, “Updating position of spatial {0}”, id);

}



public synchronized void movePlayer(final Integer id, final Vector3f newPosition) {

app.enqueue(new Callable<Void>() {

@Override

public Void call() throws Exception {

Spatial player = rootNode.getChild(id);

player.move(newPosition);

player.lookAt(newPosition, Vector3f.UNIT_Y);

return null;

}

});

}

[/java]



The problem is that the postion of other characters is often wrong like the direction of the mesh and i can’t succeed to find the trouble that causes this issue…



I hope you can find with me a solution, and any advice on how to implement in a better way this architecture is welcome :wink:

Thanks a lot!!!

A few things…

First just a note:

server.broadcast(new Filters().notEqualTo(source), message);



You do not need to instantiate Filters as it’s just a static utility class… so use:

server.broadcast(Filters.notEqualTo(source), message);



That’s not your problem, I just thought I’d point it out. :slight_smile:



I think this is your problem:

player.move(newPosition);



The Javadocs are not very clear on this point, but this method moves the spatial relative to its last position. I think you really want setLocalTranslation().



Edit: except I see you are actually sending deltas… sorry about that. I’ll look deeper.

Wait…



Is it that the objects are moving ok and that they are just pointing in the wrong direction?

Unfortunately both position and direction are often wrong… I don’t know why but for example if in the town scene i move to the statue in the center of the square and than i move behind the tallest house, the other players will see me in a wrong position that is (for instance) 100 WU distance.

I was trying also to rotate simply cubes in a ChaseCamera mode butgetting some data (like the moose-dragged movement of the camera that ,make the spatial to rotate) is really an hard stuff… I’v tryed a lot but results are always wrong…



Another question:



my PlayerManager class, like the listeners, run in a different thread from the main render thread?

How often are the clients sending messages?



It might be better to send absolute positions instead of trying to do dead-reckoning. Otherwise we will need to know a lot more about how player positions are updated and whether you are sending a message for every little movement. Because it looks like the player might be controlled by physics? If you miss even a single frame of state change then everything gets messed up.



Once you get everything working then you can explore different architectures… but sending world position and orientation is the easiest to get working.

pspeed said:
player.move(newPosition);

The Javadocs are not very clear on this point, but this method moves the spatial relative to its last position. I think you really want setLocalTranslation().


.move displaces by an offset from last position.

For those who are unsure what that means, it'll move a spatial by "newPosition" units from its last location.

Ex: if you're sitting at vector3f 1, 5, 10 and offset it by 2, then it becomes 3, 7, 12. The offset can either be a scalar or a vector3f.

That last post wasn’t directed at you Paul. :slight_smile: lol

if you want to see the source code:

http://code.google.com/p/my-jme-game/source/browse/trunk/MyGame/src/it/mygame



However the position is sent every time there’s a movement, and regarding the worl position and orientation it’s not easy for me because there are some difficulties retrieving the movement of a chasecamera and translate it into a qaternion that rotates the players and corresponding spatials in the other clients…

Well, worry about position first then… but use world position and not “relative position”… I think that’s where your problems are. And if not, the problems will be easier to debug without wondering where things are supposed to be.

I just tryed to debug it but after some steps all goes wrong and something saying that spatial aren’t updated appears and all crashes.

However i do it now

That sounds like you stopped enqueueing a callable to update the spatials. Or you will have to be more specific with the errors.

Ok, maybe i got the problem!!! But i’ve got other question about callable and multithreading:



1 - The network listeners such as the MessageReceiver and the ClientStateListener are executed in a different thread respect to the main application?



2 - The app.enqueu method for what I’ve understand enqueue a task but when this task is executed?



And something that is annoyng me for some time, how can i work with quaternions? I’ve seen repeately the SceneGraph and Math for dummies but there are things that aren’t described for example: if i have a chaseCamera that moves around a spatial, how can i rotate the spatial to face the direction the camera is pointing (what i need in only the rotation on the Y axis when the right mouse botton is pressed)? And to rotate a spatial (a geometry with a sinbad mesh attached) to face the same direction?



I know that i’m really boring!! XD But my hopes are to become enough expert with JME3 to do my job in this fantastic communuty and the only way is to ask and study… So sorry me if i’m boring you with this questions but i hope someday i will help you to develop this fantastic engine and the SDK to become more and more powerfull like the unity 3D engine :wink: With the only advantages that JME is more and more beautiful!! XD

kazeshiro said:
Ok, maybe i got the problem!!! But i've got other question about callable and multithreading:

1 - The network listeners such as the MessageReceiver and the ClientStateListener are executed in a different thread respect to the main application?


Yes, network messages are delivered on their own thread. In fact, the only guarantee that SpiderMonkey makes with respect to threading is that you will never get two messages for the same connection at the same time. (Mostly that's for the server) The server architecture supports thread-per-connection even though none of the kernel implementations actually work that way. However, you the reliable messages come in on a different thread than the unreliable... but SpiderMonkey makes sure that if they are for the same connection that you won't get them delivered at the same time.

That was probably TMI.

Bottom line, yes, networking is on a different thread(s) than the render loop.

kazeshiro said:
2 - The app.enqueu method for what I've understand enqueue a task but when this task is executed?


The rendering thread basically calls Application.update() over and over and over. The first thing Application.update() does is run any of the enqueued callables.

kazeshiro said:
And something that is annoyng me for some time, how can i work with quaternions? I've seen repeately the SceneGraph and Math for dummies but there are things that aren't described for example: if i have a chaseCamera that moves around a spatial, how can i rotate the spatial to face the direction the camera is pointing (what i need in only the rotation on the Y axis when the right mouse botton is pressed)? And to rotate a spatial (a geometry with a sinbad mesh attached) to face the same direction?

I know that i'm really boring!! XD But my hopes are to become enough expert with JME3 to do my job in this fantastic communuty and the only way is to ask and study.. So sorry me if i'm boring you with this questions but i hope someday i will help you to develop this fantastic engine and the SDK to become more and more powerfull like the unity 3D engine ;) With the only advantages that JME is more and more beautiful!! XD


[java]
float[] angles = Quaternion.toAngles(null);
...angles will now contain rotation about the x, y, and z axis.
...to translate back into just rotation about the y-axis (which is I think what you want):
Quaternion q = new Quatnernion().fromAngles( 0, angles[1], 0 );
[/java]

Ignore the Java docs calling those values "yaw, pitch, and roll" because in my experience that's completely bogus.