[jme3]multiple jbullet world and networking

Hi,

I’m going to develop a network game.

the server will have only one physic engine. It will be possible to navigate with a JME in this world, but normally it will not require graphics

the client will have 2 world physic engine: one will be synchronized with the server; every time the sync signal from server arrive, the physic world is copied in the “de-synchronized” world, witch will be updated from client.



I’m going to do this because the timestep for physic is 1/60 of seconds, for having only synchronized engine and fluid movement mean a maximum ping of 16. For example, if you have a ping of 100, you will see all thing steady and “jump” every sync.

With the asinc server, you will see things still moving following the last updated way, and you will notice them “jump” only when they change very fast their movement.

I’m going to use jbullet “vanilla”, without jme-jbullet class, for server and sync world, because they don’t need graphics (well only for debug).



Do you thing it is a good idea?

Do you have any suggestion?

One bullet unit, how many jme unit is?

there is a easy way, using Blender, to create a model and it’s physic representation in “one shot”? (i think I’ve seen something around the wiki)pre type="java"
Game Development Discussion (jME3)
/pre

I would still do all this using the API of jME3. You can use the bullet objects without any attachment to the scenegraph and you wont have to convert every single vector and quaternion etc. (jbullet does not use the same math system as jme3). Updating with 1/60 fps is not a good idea, you should only synchronize every quarter second or so but also propagate things like applying forces etc. MonkeyZone is a good example of this, you can further reduce the snapping by stepping the physics according to network delay.

Sorry, 1/60 is timestep of physic.

Modification from client are propagated to all client by server (so lag=“double ping” + one step ). maybe i can propagate client to client, but only used in asinc server, until server “ok”.

All map is updated from server every 3 or 4 seconds, just to be sure PC that make different math are still aligned.


you can use the bullet objects without any attachment to the scenegraph

it's what i was looking for :)

you wont have to convert every single vector and quaternion etc.

I haven't think about this difference, thank to point this out! then I'll use the JME3 API

sorry but i still can’t get something.

I’m using a BulletAppState for the physic. Then i start it with

bulletAppState.startPhysics();

then, i choose to start the graphics. I attach bulletAppState to a SimpleApplication. This will call internally (as API say) bulletAppState.startPhysics();… will this couse problem or is it safe?

then i have to take every object in physic space, build spatial, addcontrol(the physic object) and attach it to root node… right?



so i can switch graphics on and off at runtime right? or will this cause problem?



and finally, modification to physic (like new object or change of some value) and to graphics can be done in a parallel thread or i’ve to syncronize something?



ah, and one of the physic engine in the client (sinc world) has to be “stepped” manually, the other (ainc world) step at fixed rate of 60fps, but when syncronized with sinc world has to be stepped X time…

for example, server send the full action list for turn 54 (so client’s sinc world is at turn 53, asinc world is >=53, like 60). sinc world execute the actions and step to turn 54. if there was action, sinc world is copied over asinc world, asinc world is stepped to turn 60, and asinc can run normally until next sync.

how can this be done (step physic engine manually)?

As the javadoc states you don’t need to call startPhysics() yourself, but even if you do it will simply not be started when its attached. To step the physics differently you’ll have to implement an AppState yourself to step the physics. As said, all you want to do is implemented in MonkeyZone already, the physics stepping will (if necessary) also be built in later.

well, many of the code I’m gonna use is implemented in my old game, witch was using box2d.

It’s unfinished and it’s api is too much unclean, so I’m rewriting it from scratch but with Jbullet :slight_smile:

Thanks for help, you will hear me again :slight_smile:

still having some problem…

I’ve extended BulletAppState:

it override update: it insert the requested object to physic engine and the call super.update() (for inserting object from others thread, obj are putted in a list and then added at the update)



everything seems ok (no exception inserting new object)



then I’ve extended SimpleApplication (and here started the problem):

basic init of the cam etc… showing the floor is ok.

But if I use addBulletAppState i get the error:

[java]GRAVE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]

java.lang.NullPointerException

at java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:882)

at com.jme3.bullet.PhysicsSpace.addRigidBody(PhysicsSpace.java:549)

at com.jme3.bullet.PhysicsSpace.addCollisionObject(PhysicsSpace.java:395)

at com.jme3.bullet.control.RigidBodyControl.setPhysicsSpace(RigidBodyControl.java:250)

at com.jme3.bullet.PhysicsSpace.add(PhysicsSpace.java:377)

at TestAPIjme3Jbullet.Physics.addObjectSync(Physics.java:44)

at TestAPIjme3Jbullet.Physics.update(Physics.java:33)

at com.jme3.app.state.AppStateManager.update(AppStateManager.java:143)

at com.jme3.app.SimpleApplication.update(SimpleApplication.java:238)

at TestAPIjme3Jbullet.Graphics.update(Graphics.java:132)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:146)

at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:203)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:208)

at java.lang.Thread.run(Thread.java:662)[/java]

so I’ve removed it.



Now I’ve also overrided the update() method, so i can add new object from others thread.

If i simply add new object (without Control) everything is fine.

If I add an object with Control I only see its shadow. I’ve also tried to put some gravity in physic world, but the shadow don’t move…



ps. floor isn’t in the physic world, so i don’t think it’s a problem of “overlay” of object.



So now i can use the physic world, I can use the graphics, but I can mix them together as I want (switch graphics on and off at runtime).



Ah and i don’t understand how move the object in physic engine: if you have a spatial, you can simply use setLocalTranslation(), but Control doesn’t have it! how I’m supposed to do?

Your approach doesn’t sound very right, you should not just add objects from another thread, did you go through the tutorials and read the “best practices” document? After you do that many things will be clearer (like accessing and moving physics objects etc.).

You have picked probably one of the hardest areas to get right, but also , in my opinion, one of the most satisfying areas to investigate. I am attempting a similar thing in that I am trying to write a FPS using JME and the jbullet integration.



I write Java professionally but not game programming and not network gaming (just to put my thoughts in perspective). Some things that I have found very helpful:


  1. Look at the tutorials. They help, a lot.
  2. Download the MonkeyZone source and understand it. This was more helpful to me than the tutorials as it highlights a lot of best practices in JME. Especially study the way controllers work - they are fantastic.
  3. Study spidermonkey. It has some issues but works, and well. Dont forget to @serialize you messages…
  4. Build a basic networked game. Have the server fully authorative and only send updates to the client. The client mearly sends inputs to the server. This is simple to do and if on a LAN will works very well. I used cubes and a heightmap - it was still great!
  5. Get over the excitement of getting this working and re-factor your code into decent logistical groups. It will help as you make things more complicated; there is nothing worse than changing the same thing in 2 places for the 10th time…
  6. Add advanced features. So far I have added client side interpolation and am looking at putting client side prediction in. There are a lot of articles out there on the Source engine etc. Try and read them all and then understand them. I have done ok on the reading part…



    Note that I have not used the MonkeyZone base. This is for no reason other than this was/is an excercise for me to write my own network game and understand the logic behind the theory.



    I hope this does not sound condescending , that is not its intention!



    Matt
1 Like

I’m not adding objects from another thread, I’m putting them in an LinkedList (syncronized) and then add them from update() Overrided method.



The problem is that i have a full populated physic world, and I’m tryng to add physic world to an empty SimpleApplication.



My code is simply https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:beginner:hello_physics?s[]=jbullet

rewritten in a way that Graphics is independent from physic: SimpleApplication can be closed, and physic will still run, and then SimpleApplication can be restared.

This is not strictly necessary for my game, just a nice feature.



Actually I’ve studied the structure of the game’s classes and iteration, based on the old one. Actually i know where and what class I’ve to implement and what they have to do.


Ah and i don’t understand how move the object in physic engine: if you have a spatial, you can simply use setLocalTranslation(), but Control doesn’t have it! how I’m supposed to do?

I answer myself: I don't have to use Control, i have to use PhysicsControl :D

now I'm gonna do some other test...

Well ok, but I’d suggest getting to know the engine without such modifications first, after the third of these we wont be able to help you much anymore :wink:

ok now it works :slight_smile: yeeeeeee :smiley:


I answer myself: I don’t have to use Control, i have to use PhysicsControl :D

worng again, i WAS using PhysicsControl. I have to use RigidPhysicsControl (luckly everything is rigid... well not the GhostControl like radar and shield, but they will not be moved directly, they will be attached at CollisionShape :D)

using RigidBodyControl instead PhysicsControl solved the above problem, probably because PhysicsControl is an interface... (but i still can't get the error... the interface was losing hash? because the function is not implemented in Interface, wasn't it supposed to use its stored implementation, that was the RigidPhysicsControl? like polymorphism?)
now i can do graphics.addBulletAppState( physic ); without error!
add pre-existent physic object to graphics, create new physic object, and obviously create only graphic object.
Ah, and here why i was only seeing the shadow: when the object was added to graphics, its position was changed to cam location! lol
if I don't use graphics.addBulletAppState( physic ); simply the object will not move, like physic engine is stopped (and i think this is ok, it make sense :D )

Thats what I mean, I have absolutely no idea what you are talking about.

uhh what you don’t understand? sorry but I don’t speak very well English :smiley:

I’ve say I’ve changed PhysicsControl with RigidPhysicsControl and everything started to work.



little problem: you can’t add physic object one above the other, normally in jbullet i do a convexSweepTest on the dinamic world, if the resultCallback report a hit I change randomly the creation coordinate and start again the check.

from PhysicsSpace I can do rayTest, but no convexSweepTest…

API also say: “getDynamicsWorld() used internally”… is safe call getDynamicsWorld().convexSweepTest(blabla)?

lesto said:
API also say: "getDynamicsWorld() used internally".. is safe call getDynamicsWorld().convexSweepTest(blabla)?

No its not. I still have to wrap the convex test api, but you can use a GhostObject.

I added PhysicsSpace.sweepTest in svn.

lol thanks, I’m going to download it :slight_smile:

Just wait until tomorrow and update jMP when its in the nightly.

I’m using sweepTest() to see if the zone is clear, to add a new physic object without weird things.

Some raccomandation:

sweepTest have to use different Transform start and Transform end ( at least distance > 0.4f, it’s a know bug, in new bullet you can use contactTest for this kind of test)

sweepTest will not see a collision if it start INSIDE an object and is moving AWAY from its centre.



so here the code I’m using to see if location “actualPosition” is free form obstacles:

[java]

private int testIfFreePosition(RigidBodyControl physic) {

int numCollidingObj=0;

Transform actualPosition = new Transform(physic.getPhysicsLocation(), physic.getPhysicsRotation() );

Transform nextFakePosition = actualPosition.clone();



//basic test

nextFakePosition.setTranslation(actualPosition.getTranslation().x+1, actualPosition.getTranslation().y+1, actualPosition.getTranslation().z+1);

List<PhysicsSweepTestResult> ris = getPhysicsSpace().sweepTest(physic.getCollisionShape(), actualPosition, nextFakePosition);

numCollidingObj+=ris.size();



//meybe we was INSIDE an object and we was moving away, so test in the other direction. This will also work if actualPosition is in the center of the other colliding object

ris = getPhysicsSpace().sweepTest(physic.getCollisionShape(), nextFakePosition, actualPosition );

numCollidingObj+=ris.size();



return numCollidingObj;

}

[/java]

Hm I use only serveside logic, and a tickrate of 75ms, the client interpolates between the recived positions so you kinda look back 75+ping seconds. This actually feels kinda fluent when a little prediction is added (when pressing w the camera moves forward without waiting for the synch for example)