Cloning a Spatial

Why the method clone() of a Spatial clones its parent?
For example my case:

final Node oldElement = (Node) node.getElement();
final Node newElement = (Node) oldElement.clone();

I want clone the node and its children, but this method clones the node, its children and its parent. So I have this problem :frowning:

java.lang.IllegalArgumentException: Object is not cloneable, type:class com.ss.editor.model.EditorCamera
	at com.jme3.util.clone.Cloner.clone(Cloner.java:269)
	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:1422)
	at com.jme3.scene.Node.cloneFields(Node.java:726)
	at com.jme3.util.clone.Cloner.clone(Cloner.java:255)
	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.Node.cloneFields(Node.java:733)
	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.cloneFields(Spatial.java:1416)
	at com.jme3.scene.Node.cloneFields(Node.java:726)
	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.cloneFields(Spatial.java:1416)
	at com.jme3.scene.Node.cloneFields(Node.java:726)
	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.cloneFields(Spatial.java:1416)
	at com.jme3.scene.Node.cloneFields(Node.java:726)
	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:1289)
	at com.jme3.scene.Node.clone(Node.java:684)
	at com.jme3.scene.Node.clone(Node.java:62)
	at com.jme3.scene.Spatial.clone(Spatial.java:1368)

Given the size of your stack trace, it’s not the parent of the root that you are cloning… it’s some child deep down. Else something else weird.

Because right as the beginning of Spatial’s clone method:

    public Spatial clone( boolean cloneMaterial ) {

        // Setup the cloner for the type of cloning we want to do.
        Cloner cloner = new Cloner();

        // First, we definitely do not want to clone our own parent
        cloner.setClonedValue(parent, null);

 ...

So I will need to know more about your scene hierarchy and which element you are actually cloning.

What is EditorCamera? A control?

Wait. I may have found the bug.

I found in the Spatial:

this.parent = cloner.clone(parent);

In the method cloneFields()

Yes, but as I said this is supposed to return null because it’s been ‘pre-cloned’ in the cloner. Cloner has a bug, though.

A line:

        if( clone != null ) {

…needs to be…

        if( clone != null || index.containsKey(object) ) {

I’m committing a fix to master now.

Fix committed. I don’t know if you are setup to build from head. If you are then you could try it and see it fixes your issue.

A temporary but ugly work-around would be to null out the parent before you clone.

I wait when @nehon will merge master branch to PBR branch, because I use my branch, which is merge master with PBR.

Well, you could always cherry pick that one file if you are in a hurry.

Edit: its the com.jme3.util.clone.Cloner class that I changed.

My current workaround: :smile:

final Node oldElement = (Node) node.getElement();
//FIXME потом надо убрать, как с клонированием разберусь
final Node parent = oldElement.getParent();
oldElement.removeFromParent();

final Node newElement = (Node) oldElement.clone();

parent.attachChild(oldElement);