JME3 Crashed from RigidBodyControl with a mass of 0

I’ve ported the cubes framework for JME3 and I’m trying to load a save with the serialized data written to a file, I load the file like normal. However, when BlockTerrainControl runs one of the listeners on addChunk, it crashes the game. This ONLY happens when loading a save. If anyone knows how to fix this, please reply.
Snippet of addChunkListener:

this.blockTerrain.addChunkListener(new BlockChunkListener() {
    @Override
    public void onSpatialUpdated(BlockChunkControl blockChunk) {
        Geometry optimizedGeometry = blockChunk.getOptimizedGeometry_Opaque();
        RigidBodyControl rigidBodyControl = optimizedGeometry.getControl(RigidBodyControl.class);
        if(rigidBodyControl == null) {
            rigidBodyControl = new RigidBodyControl(0f);
            optimizedGeometry.addControl(rigidBodyControl);
            bulletAppState.getPhysicsSpace().add(rigidBodyControl);
        }
        rigidBodyControl.setCollisionShape(new MeshCollisionShape(optimizedGeometry.getMesh()));
    }
});

Output:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007fe1394bd73f, pid=12614, tid=0x00007fe138e92700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_111-b14) (build 1.8.0_111-b14)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.111-b14 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libbulletjme.so+0x9273f]  btQuantizedBvh::buildTree(int, int)+0x3df
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/spaceboyross/Documents/Blocks/hs_err_pid12614.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

Engine version?

v3.2.0-prealpha-sdk1

Mhh can you provide a small test case?

I can only provide the function that crashes.
Snippet:

this.cubesSettings = Blocks.getSettings(this);
    if(this.nifty.getGlobalProperties().containsKey("newgame") && (Boolean)this.nifty.getGlobalProperties().get("newgame") == true) {
        this.blockTerrain = new BlockTerrainControl(this.cubesSettings,new Vector3Int(14,2,7));
        this.blockTerrain.setBlocksFromNoise(new Vector3Int(),this.terrainSize,0.1f,Blocks.getBlockByID("blocks:block.grass"));
        for(int i = 0;i < Blocks.getBlockCount();i++) this.blockTerrain.setBlock(this.terrainSize.getX()/2,this.terrainSize.getY()-5,(this.terrainSize.getZ()/2)+i+1,Blocks.getBlockByIndex(i));
        BinaryImporter importer = BinaryImporter.getInstance();
        BinaryExporter exporter = BinaryExporter.getInstance();
        try {
            GameSaveConfig gsc = (GameSaveConfig)importer.load(new File(this.nifty.getGlobalProperties().getProperty("path")+"game.save"));
            gsc.setSeed(CubesSerializer.writeToBytes(this.blockTerrain));
            exporter.save(gsc,new File(this.nifty.getGlobalProperties().getProperty("path")+"game.save"));
        } catch(IOException ex) {
            Logger.getLogger(BlocksGame.class.getName()).log(Level.SEVERE,null,ex);
        }
        this.blockTerrain.addChunkListener(new BlockChunkListener() {
            @Override
            public void onSpatialUpdated(BlockChunkControl blockChunk) {
                Geometry optimizedGeometry = blockChunk.getOptimizedGeometry_Opaque();
                RigidBodyControl rigidBodyControl = optimizedGeometry.getControl(RigidBodyControl.class);
                if(rigidBodyControl == null) {
                    rigidBodyControl = new RigidBodyControl(0);
                    optimizedGeometry.addControl(rigidBodyControl);
                    bulletAppState.getPhysicsSpace().add(rigidBodyControl);
                }
                rigidBodyControl.setCollisionShape(new MeshCollisionShape(optimizedGeometry.getMesh()));
            }
        });
    } else {
        BinaryImporter importer = BinaryImporter.getInstance();
        try {
            GameSaveConfig gsc = (GameSaveConfig)importer.load(new File(this.nifty.getGlobalProperties().getProperty("path")+"game.save"));
            BitInputStream is = new BitInputStream(new ByteArrayInputStream(gsc.getSeed()));
            int chunksCountX = is.readInteger();
            int chunksCountY = is.readInteger();
            int chunksCountZ = is.readInteger();
            this.blockTerrain = new BlockTerrainControl(this.cubesSettings,new Vector3Int(chunksCountX,chunksCountY,chunksCountZ));
            for(int x = 0;x < chunksCountX;x++) {
                for(int y = 0;y < chunksCountY;y++) {
                    for(int z = 0;z < chunksCountZ;z++) {
                        this.blockTerrain.getChunks()[x][y][z].read(is);
                    }
                }
            }
            this.blockTerrain.addChunkListener(new BlockChunkListener() {
                @Override
                public void onSpatialUpdated(BlockChunkControl blockChunk) {
                    Geometry optimizedGeometry = blockChunk.getOptimizedGeometry_Opaque();
                    RigidBodyControl rigidBodyControl = optimizedGeometry.getControl(RigidBodyControl.class);
                    if(rigidBodyControl == null) {
                        rigidBodyControl = new RigidBodyControl(0f);
                        optimizedGeometry.addControl(rigidBodyControl);
                        bulletAppState.getPhysicsSpace().add(rigidBodyControl);
                    }
                    rigidBodyControl.setCollisionShape(new MeshCollisionShape(optimizedGeometry.getMesh()));
                }
            });
        } catch(IOException ex) {
            Logger.getLogger(BlocksGame.class.getName()).log(Level.SEVERE,null,ex);
        }
    }
    this.terrainNode.addControl(this.blockTerrain);
    this.terrainNode.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);

If you make a self contained testcase (http://sscce.org/) that i can run without external dependencies (other than jme and the j3o file ofc) i can test it against the master branch and the latest bullet, otherwise you’ll have to do it yourself but if you are using the sdk it might be not so easy.

1 Like

I changed around the Cubes framework TestPhysics example to have the crash that I’m experiencing to occur.

Code:

package com.cubes.test;

import java.util.logging.Level;
import java.util.logging.Logger;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.MeshCollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.system.AppSettings;
import com.cubes.*;
import com.cubes.network.CubesSerializer;

public class TestPhysics extends SimpleApplication implements ActionListener{

public static void main(String[] args){
    Logger.getLogger("").setLevel(Level.SEVERE);
    TestPhysics app = new TestPhysics();
    app.start();
}

public TestPhysics(){
    settings = new AppSettings(true);
    settings.setWidth(1280);
    settings.setHeight(720);
    settings.setTitle("Cubes Demo - Physics");
    settings.setFrameRate(60);
}
private final Vector3Int terrainSize = new Vector3Int(100, 30, 100);
private BulletAppState bulletAppState;
private CharacterControl playerControl;
private Vector3f walkDirection = new Vector3f();
private boolean[] arrowKeys = new boolean[4];
private CubesSettings cubesSettings;
private BlockTerrainControl blockTerrain,blockTerrainClone;
private Node terrainNode,terrainNodeClone = new Node();

@Override
public void simpleInitApp(){
    bulletAppState = new BulletAppState();
    stateManager.attach(bulletAppState);
    initControls();
    initBlockTerrain();
    initPlayer();
    cam.lookAtDirection(new Vector3f(1, 0, 1), Vector3f.UNIT_Y);
}

private void initControls(){
    inputManager.addMapping("move_left", new KeyTrigger(KeyInput.KEY_A));
    inputManager.addMapping("move_right", new KeyTrigger(KeyInput.KEY_D));
    inputManager.addMapping("move_up", new KeyTrigger(KeyInput.KEY_W));
    inputManager.addMapping("move_down", new KeyTrigger(KeyInput.KEY_S));
    inputManager.addMapping("jump", new KeyTrigger(KeyInput.KEY_SPACE));
    inputManager.addListener(this, "move_left");
    inputManager.addListener(this, "move_right");
    inputManager.addListener(this, "move_up");
    inputManager.addListener(this, "move_down");
    inputManager.addListener(this, "jump");
}

private void initBlockTerrain(){
    CubesTestAssets.registerBlocks();
    CubesTestAssets.initializeEnvironment(this);
    
    cubesSettings = CubesTestAssets.getSettings(this);
    blockTerrain = new BlockTerrainControl(cubesSettings, new Vector3Int(7, 1, 7));
    blockTerrain.setBlocksFromNoise(new Vector3Int(), terrainSize, 0.8f, CubesTestAssets.BLOCK_GRASS);
    blockTerrain.addChunkListener(new BlockChunkListener(){

        @Override
        public void onSpatialUpdated(BlockChunkControl blockChunk){
            Geometry optimizedGeometry = blockChunk.getOptimizedGeometry_Opaque();
            RigidBodyControl rigidBodyControl = optimizedGeometry.getControl(RigidBodyControl.class);
            if(rigidBodyControl == null){
                rigidBodyControl = new RigidBodyControl(0);
                optimizedGeometry.addControl(rigidBodyControl);
                bulletAppState.getPhysicsSpace().add(rigidBodyControl);
            }
            rigidBodyControl.setCollisionShape(new MeshCollisionShape(optimizedGeometry.getMesh()));
        }
    });
    
    blockTerrainClone = new BlockTerrainControl(CubesTestAssets.getSettings(this), new Vector3Int());
    
    byte[] serializedBlockTerrain = CubesSerializer.writeToBytes(blockTerrain);
    CubesSerializer.readFromBytes(blockTerrainClone, serializedBlockTerrain);
    blockTerrainClone.addChunkListener(new BlockChunkListener(){

        @Override
        public void onSpatialUpdated(BlockChunkControl blockChunk){
            Geometry optimizedGeometry = blockChunk.getOptimizedGeometry_Opaque();
            RigidBodyControl rigidBodyControl = optimizedGeometry.getControl(RigidBodyControl.class);
            if(rigidBodyControl == null){
                rigidBodyControl = new RigidBodyControl(0);
                optimizedGeometry.addControl(rigidBodyControl);
                bulletAppState.getPhysicsSpace().add(rigidBodyControl);
            }
            rigidBodyControl.setCollisionShape(new MeshCollisionShape(optimizedGeometry.getMesh()));
        }
    });
    terrainNode.addControl(blockTerrain);
    terrainNode.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
    terrainNodeClone.addControl(blockTerrainClone);
    terrainNodeClone.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
    rootNode.attachChild(terrainNodeClone);
    rootNode.attachChild(terrainNode);
}

private void initPlayer(){
    playerControl = new CharacterControl(new CapsuleCollisionShape((cubesSettings.getBlockSize() / 2), cubesSettings.getBlockSize() * 2), 0.05f);
    playerControl.setJumpSpeed(25);
    playerControl.setFallSpeed(20);
    playerControl.setGravity(70);
    playerControl.setPhysicsLocation(new Vector3f(5, terrainSize.getY() + 5, 5).mult(cubesSettings.getBlockSize()));
    bulletAppState.getPhysicsSpace().add(playerControl);
}

@Override
public void simpleUpdate(float lastTimePerFrame){
    float playerMoveSpeed = ((cubesSettings.getBlockSize() * 6.5f) * lastTimePerFrame);
    Vector3f camDir = cam.getDirection().mult(playerMoveSpeed);
    Vector3f camLeft = cam.getLeft().mult(playerMoveSpeed);
    walkDirection.set(0, 0, 0);
    if(arrowKeys[0]){ walkDirection.addLocal(camDir); }
    if(arrowKeys[1]){ walkDirection.addLocal(camLeft.negate()); }
    if(arrowKeys[2]){ walkDirection.addLocal(camDir.negate()); }
    if(arrowKeys[3]){ walkDirection.addLocal(camLeft); }
    walkDirection.setY(0);
    playerControl.setWalkDirection(walkDirection);
    cam.setLocation(playerControl.getPhysicsLocation());
}

@Override
public void onAction(String actionName, boolean value, float lastTimePerFrame){
    if(actionName.equals("move_up")){
        arrowKeys[0] = value;
    }
    else if(actionName.equals("move_right")){
        arrowKeys[1] = value;
    }
    else if(actionName.equals("move_left")){
        arrowKeys[3] = value;
    }
    else if(actionName.equals("move_down")){
        arrowKeys[2] = value;
    }
    else if(actionName.equals("jump")){
        playerControl.jump();
    }
    }
}

Ok, i still need the cube library though, you are not using the one available in the contrib repo because it’s for jme 3.0 only right?

I got it from GitHub - jMonkeyEngine-Contributions/cubes, I made it compatible by using JME’s built in tool for changing the version.

yes, can you post it?

Also, does it work if you regenerate the rigidbody every time you load the mesh?