Spatials can't carry their controls correctly after convertion in j3o

Hello guys,

I want to convert a scenegraph in j3o including their controls. So I create a class (ObjectControl) that extends GhostControl and I implement Savable and I override read() and write() following this tutorial: https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:save_and_load . The problem is that when I load the scene, the controls of the spatials don’t respond. When I run the debugger I see that each spatial has a control attached but Its type is GhostControl and not ObjectControl. Here’s my code:

[java]public class SavableAppState extends AbstractAppState {

private Node rootNode;
private Main app;
private AssetManager assetManager;

@Override
public void initialize(AppStateManager stateManager, Application app) {
    super.initialize(stateManager, app);
    this.app = (Main) app;
    rootNode = this.app.getRootNode();
    assetManager = this.app.getAssetManager();
    setGame();
    writeSceneGraph();
    loadLevel();
}

public void setGame() {
    float size = 5f;
    Mesh box = new Box(size, size, size);
    Geometry geom = new Geometry("box", box);
    Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat.setColor("Color", ColorRGBA.Blue);
    geom.setMaterial(mat);
    CollisionShape shape = new BoxCollisionShape(new Vector3f(0.5f, 0.5f, 0.5f));
    geom.addControl(new ObjectControl(shape));
    rootNode.attachChild(geom);
}

public void writeSceneGraph() {
    String userDir = System.getProperty("user.dir");
    BinaryExporter exporter = BinaryExporter.getInstance();
    File file = new File(userDir + "/assets/Models/" + "MyModel.j3o");
    try {
        exporter.save(rootNode, file);
    } catch (IOException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Error: Failed to save game!", ex);
    }
}

public void loadLevel() {
    String userDir = System.getProperty("user.dir");

    assetManager.registerLocator(userDir, FileLocator.class);
    Node loadedNode = (Node) assetManager.loadModel("assets/Models/MyModel.j3o");
    loadedNode.setName("loadnode");
    rootNode.attachChild(loadedNode);
}

}[/java]

[java]
public class ObjectControl extends GhostControl implements Savable {
private int health;

public ObjectControl() {
    health = 100;
}

public ObjectControl(CollisionShape shape) {
    super(shape);
    health = 100;
}

@Override
public void write(JmeExporter ex) throws IOException {
    
    OutputCapsule capsule = ex.getCapsule(this);
    capsule.write(health, "health", 100);
    super.write(ex);
}

@Override
public void update(float tpf) {
    super.update(tpf);
    Quaternion rotation = new Quaternion().fromAngleAxis(tpf * 1, Vector3f.UNIT_Y);
    spatial.rotate(rotation);
}

@Override
public void read(JmeImporter im) throws IOException {        
    InputCapsule capsule = im.getCapsule(this);
    health = capsule.readInt("health", 100);
    super.read(im);
}

}[/java]

@SeriousGamer said: Hello guys,

I want to convert a scenegraph in j3o including their controls. So I create a class (ObjectControl) that extends GhostControl and I implement Savable and I override read() and write() following this tutorial: https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:save_and_load . The problem is that when I load the scene, the controls of the spatials don’t respond. When I run the debugger I see that each spatial has a control attached but Its type is GhostControl and not ObjectControl. Here’s my code:

[java]public class SavableAppState extends AbstractAppState {

private Node rootNode;
private Main app;
private AssetManager assetManager;

@Override
public void initialize(AppStateManager stateManager, Application app) {
    super.initialize(stateManager, app);
    this.app = (Main) app;
    rootNode = this.app.getRootNode();
    assetManager = this.app.getAssetManager();
    setGame();
    writeSceneGraph();
    loadLevel();
}

public void setGame() {
    float size = 5f;
    Mesh box = new Box(size, size, size);
    Geometry geom = new Geometry("box", box);
    Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat.setColor("Color", ColorRGBA.Blue);
    geom.setMaterial(mat);
    CollisionShape shape = new BoxCollisionShape(new Vector3f(0.5f, 0.5f, 0.5f));
    geom.addControl(new ObjectControl(shape));
    rootNode.attachChild(geom);
}

public void writeSceneGraph() {
    String userDir = System.getProperty("user.dir");
    BinaryExporter exporter = BinaryExporter.getInstance();
    File file = new File(userDir + "/assets/Models/" + "MyModel.j3o");
    try {
        exporter.save(rootNode, file);
    } catch (IOException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Error: Failed to save game!", ex);
    }
}

public void loadLevel() {
    String userDir = System.getProperty("user.dir");

    assetManager.registerLocator(userDir, FileLocator.class);
    Node loadedNode = (Node) assetManager.loadModel("assets/Models/MyModel.j3o");
    loadedNode.setName("loadnode");
    rootNode.attachChild(loadedNode);
}

}[/java]

[java]
public class ObjectControl extends GhostControl implements Savable {
private int health;

public ObjectControl() {
    super();
    health = 100;
}

public ObjectControl(CollisionShape shape) {
    super(shape);
    health = 100;
}

@Override
public void write(JmeExporter ex) throws IOException {
    super.write(ex);
    OutputCapsule capsule = ex.getCapsule(this);
    capsule.write(health, "health", 100);        
}

@Override
public void update(float tpf) {
    super.update(tpf);
    Quaternion rotation = new Quaternion().fromAngleAxis(tpf * 1, Vector3f.UNIT_Y);
    spatial.rotate(rotation);
}

@Override
public void read(JmeImporter im) throws IOException {
    super.read(im);
    InputCapsule capsule = im.getCapsule(this);
    health = capsule.readInt("health", 100);        
}

}[/java]


EDIT: I ve done some minor changes to my code

As discussed in another thread, because GhostControl’s clone() method self-creates instead of calling super.clone() (really unfortunate) then you have to manually override it in any subclasses or it will just continue to create the super class.

Most controls don’t require this, I guess.