Saving extended RigidBodyControl in jme3.1

Hi,

I’m using the most recent snapshot of the jme3.1 engine and SDK with jBullet libraries.
I have tried to move an old project to the new SDK. Unfortunately i extended RigidBodyControl (don’t ask why ;)). I have problems with saving a spatial with this control attached. Maybe there are problems with the cloning methods?

I recreated the problem in a simple testcase:

Main.java:

package mygame;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.AssetManager;
import com.jme3.asset.DesktopAssetManager;
import com.jme3.asset.plugins.FileLocator;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.export.binary.BinaryExporter;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This is the Main Class of your Game. You should only do initialization here.
 * Move your Logic into AppStates or Controls
 *
 * @author normenhansen
 */
public class Main extends SimpleApplication {

BulletAppState bulletAppState;

public static void main(String[] args) {
    Main app = new Main();
    app.start();
}

@Override
public void simpleInitApp() {
    bulletAppState = new BulletAppState();
    stateManager.attach(bulletAppState);
    
    Box b = new Box(1, 1, 1);
    Geometry geom = new Geometry("Box", b);
    
    Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat.setColor("Color", ColorRGBA.Blue);
    geom.setMaterial(mat);

   CustomRBControl control = new CustomRBControl();
    geom.addControl(control);
    bulletAppState.getPhysicsSpace().add(control);     
    
    
    rootNode.attachChild(geom);
    
    save(System.getProperty("user.home") + "\\Documents\\"+"test.j3o");
    rootNode.detachAllChildren();
    ((DesktopAssetManager)assetManager).clearCache();
    load(System.getProperty("user.home") + "\\Documents\\", "test.j3o");
    
}

@Override
public void simpleUpdate(float tpf) {
    //TODO: add update code
}

@Override
public void simpleRender(RenderManager rm) {
    //TODO: add render code
}

public boolean save(String filePath) {
    BinaryExporter exporter = BinaryExporter.getInstance();
    File file = new File(filePath);
    try {
        exporter.save(rootNode.getChild("Box"), file);
    } catch (IOException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Error: Failed to save game!", ex);
        return false;
    }        
    return true;
}

public boolean load(String parentPath, String fileName) {
    assetManager.registerLocator(parentPath, FileLocator.class);        
    Geometry geom = (Geometry) assetManager.loadModel(fileName);
    rootNode.attachChild(geom);
    return true;        
}

}

CustomRBControl extends RigidBodyControl and has an empty body.

In jme3.0 this code runs as expected. When running this code in jme3.1 the output reads:

Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.ClassCastException: Cannot cast com.jme3.bullet.control.RigidBodyControl to mygame.CustomRBControl
	at java.lang.Class.cast(Class.java:3369)
	at com.jme3.util.clone.Cloner.clone(Cloner.java:276)
	at com.jme3.util.clone.Cloner.clone(Cloner.java:160)
	at com.jme3.util.clone.ListCloneFunction.cloneFields(ListCloneFunction.java:66)
	at com.jme3.util.clone.ListCloneFunction.cloneFields(ListCloneFunction.java:43)
	at com.jme3.util.clone.Cloner.clone(Cloner.java:228)
	at com.jme3.util.clone.Cloner.clone(Cloner.java:160)
	at com.jme3.scene.Spatial.cloneFields(Spatial.java:1505)
	at com.jme3.scene.Geometry.cloneFields(Geometry.java:560)
	at com.jme3.util.clone.Cloner.clone(Cloner.java:255)
	at com.jme3.util.clone.Cloner.clone(Cloner.java:160)
	at com.jme3.scene.Spatial.clone(Spatial.java:1360)
	at com.jme3.scene.Geometry.clone(Geometry.java:496)
	at com.jme3.scene.Geometry.clone(Geometry.java:537)
	at com.jme3.scene.Geometry.clone(Geometry.java:62)
	at com.jme3.asset.CloneableAssetProcessor.createClone(CloneableAssetProcessor.java:48)
	at com.jme3.asset.DesktopAssetManager.registerAndCloneSmartAsset(DesktopAssetManager.java:317)
	at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:379)
	at com.jme3.asset.DesktopAssetManager.loadModel(DesktopAssetManager.java:416)
	at com.jme3.asset.DesktopAssetManager.loadModel(DesktopAssetManager.java:420)
	at mygame.Main.load(Main.java:85)
	at mygame.Main.simpleInitApp(Main.java:57)
	at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:220)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:130)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:211)
	at java.lang.Thread.run(Thread.java:745)
1 Like

In JME 3.1 your custom class also as to override the method jmeClone(). Currently its using the RigidBodyControl’s jmeClone method and that’s why its returning a RigidBodyControl.

2 Likes

I didn’ know that. Thank you very much.

Normally you wouldn’t necessarily have to override that method but RigidBodyControl never properly implemented clone so super.clone(), etc. didn’t work. The cloneForSpatial() was copied directly and it directly instantiates a RigidBodyControl.

… you must have had your own cloneForSpatial() method before else you’d have had the same problem on 3.0 I guess. JME no longer uses cloneForSpatial().

1 Like