[SOLVED]Clone exception

Trying to clone a node to explore cloning.

One of the controls is just a class extending BetterCharacterControl implementing ActionListener.

java.lang.ClassCastException: Cannot cast com.jme3.bullet.control.BetterCharacterControl to mygame.controls.PCControl
	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:1506)
	at com.jme3.scene.Node.cloneFields(Node.java:723)
	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:1361)
	at com.jme3.scene.Node.clone(Node.java:682)
	at com.jme3.scene.Node.clone(Node.java:62)
	at com.jme3.scene.Spatial.clone(Spatial.java:1449)
	at mygame.appstates.PCState.cloneSpatialControl(PCState.java:122)
	at mygame.appstates.PCState.onEnable(PCState.java:106)
	at com.jme3.app.state.BaseAppState.initialize(BaseAppState.java:127)
	at com.jme3.app.state.AppStateManager.initializePending(AppStateManager.java:251)
	at com.jme3.app.state.AppStateManager.update(AppStateManager.java:281)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:236)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:193)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:232)
	at java.lang.Thread.run(Thread.java:745)

BUILD SUCCESSFUL (total time: 6 seconds)

I have tried using Cloner and just cloning the Node directly like so,

    private void cloneCheck() {
        Node newNode = charNode.clone(false);
        
        for (int i = 0; i < newNode.getNumControls(); i++) {
            System.out.println("Cloned Control" + newNode.getControl(i));
        }
    }

Am I doing something wrong here?

Try making a testcase for it (start from test jme app, do a node.clone etc.) then see if that breaks. If it does you can post it here for reference.

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.bullet.control.BetterCharacterControl;
import com.jme3.input.controls.ActionListener;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Node;

/**
 * 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 {

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

    @Override
    public void simpleInitApp() {
        Node charNode = new Node("testControlNode");
        charNode.addControl(new BCControl(1, 1, 1));
        cloneCheck(charNode);
    }

    private void cloneCheck(Node node) {
        Node newNode = node.clone(false);
    }
    
    public class BCControl extends BetterCharacterControl implements ActionListener {

        public BCControl(float radius, float height, float mass) {
            super(radius, height, mass);
        }

        @Override
        public void update(float tpf) {

        }

        @Override
        public void onAction(String name, boolean isPressed, float tpf) {

        }

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

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

}

I am calling the clone from an AppState onEnable() in the other app BTW.

In order for cloning to work, you need to tell JME how to clone a BCControl. One way to do this would be to
define a jmeClone() method for BCControl, something like this:

        @Override
        public BCControl jmeClone() {
            try {
                BCControl clone = (BCControl) super.clone();
                return clone;
            } catch (CloneNotSupportedException exception) {
                throw new RuntimeException(exception);
            }
        }
1 Like

That did it. Thank you.

1 Like