Libgdx Application terminate in an unusual way

I am developing simple multiplayer game using libgdx and box2D. And Im getting error below.

This application has requested the Runtime to terminate it in an unusual way.
AL lib: (EE) alc_cleanup: 1 device not closed
Assertion failed!

Program: C:\Program Files\Java\jre7\bin\javaw.exe
File: /var/lib/jenkins/workspace/libgdx/gdx/jni/Box2D/Dynamics/b2Body.cpp, Line 419

Expression: m_world->IsLocked() == false


I checked similar issue in SO which suggest that I may cause if we destroy Body before our World Stepping but its not case here. While trying to debug this error I found that following code is causing error:

public void updateScene(PlayerStatus playerStatus){
Vector2 pos = playerStatus.getPosition();
Player coopPlayer = coopPlayers.get(playerStatus.getId());
if (coopPlayer !=null){
coopPlayer.b2body.setTransform(pos, 0);     //Main cause of error
coopPlayer.setPosition(pos.x - coopPlayer.getWidth() / 2, pos.y - coopPlayer.getHeight() / 2);
}
}


Any help is greatly appreciated.

According to the code of Box2D, the setTransform method shouldn't be called when the world is locked. Box2D hasn't finished it simulation stage and so don't accept new changes.

You can fix this issue by calling this method only when the world isn't locked :

 if(coopPlayer != null && !yourWorld.isLocked()) {
coopPlayer.b2body.setTransform(pos, 0);
}

• thnx for your info.. but it doesnt solve the issue. – Crawler Nov 22 '16 at 16:23
• it should What have you changed ? – dwursteisen Nov 22 '16 at 16:26

I agree with dwursteisen's analysis of the problem and that you'll need to call setTransform while the world is not locked. You'll seemingly need to solve the problem differently however since you still need the setTransform to get called. I say seemingly, because you'd written in the comments that "it doesn't solve the issue" presumably because you're not getting the transform to happen all though you're not getting the error anymore either. If you are getting the same error, then you'll need to find where else in your code (in addition to updateScene) that you could be calling setTransform.

Assuming that you're no longer getting the error though...

Instead of simply checking in updateScene whether the world is unlocked and only then calling the setTransform method, you'll need to add an else clause for when coopPlayer != null and the world is locked. In this else clause, you'll need to effectively enqueue the body and new position information such that it can be later dequeued in your main loop, after the world step has been performed, and call setTransform with those queued up positions for the bodies then.

The updateScene code then might look like:

public void updateScene(PlayerStatus playerStatus){
Vector2 pos = playerStatus.getPosition();
Player coopPlayer = coopPlayers.get(playerStatus.getId());
if (coopPlayer !=null){
if (yourWorld.isLocked()) {
yourWorldState.enqueueTransform(playerStatus.getId(), pos);
}
else {
coopPlayer.b2body.setTransform(pos, 0);     //Main cause of error
coopPlayer.setPosition(pos.x - coopPlayer.getWidth() / 2, pos.y - coopPlayer.getHeight() / 2);
}
}
}


And your main loop code would look like:

while (gameShouldRun) {
world.step(...);
while (!transformQueue.empty()) {
Data data = transformQueue.dequeue();
Player coopPlayer = coopPlayers.get(data.getId());
Vector2 pos = data.getPos();
coopPlayer.b2body.setTransform(pos, 0);
coopPlayer.setPosition(pos.x - coopPlayer.getWidth() / 2, pos.y - coopPlayer.getHeight() / 2);
}
}


Of course if you know things like that only one transform will need to be done for only one body, the whole queuing concept simplifies down. Perhaps to something like just a variable to save the single new position (instead of more complex structures like an actual multi-element queue).

Hope this solves the issue entirely now.