SaveGame .saveGame() ok, .loadGame() missing objects?

[jump to the test case here]

for SaveGame.saveGame(...) I provide a simple Savable (A) that loops on a list of other Savables (B).

So A.write() calls many times OutputCapsule.write(B,name,null).
The compressed save is created, therefore I cant be sure what is there even using hex editor, so despite it seems to save I cant confirm that.

But when I try to .loadGame(…), the A.read(JmeImporter) works fine, but when, from it I call B.read(JmeImporter im), the B class is missing at JmeImporter, so:
im.getCapsule((B)this);
returns null…

After debugging I still dont understand, what could be going on?

Code would be easier to debug.

1 Like

I will make a test case.

package tests;

import java.io.IOException;
import java.util.ArrayList;

import jme3tools.savegame.SaveGame;

import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.export.Savable;

public class SaveGameFailToLoad {
	public static void main(String[] args) {
		bList.add(new B());
		bList.add(new B());
		
		SaveGame.saveGame(SaveGameFailToLoad.class.getSimpleName(), "TestSave", new A());
		SaveGame.loadGame(SaveGameFailToLoad.class.getSimpleName(), "TestSave");
	}
	
	public static class A implements Savable{
		@Override
		public void write(JmeExporter ex) throws IOException {
			OutputCapsule oc = ex.getCapsule(this);
			for(B b:bList){
				oc.write(b, "B", null);
			}
		}
		@Override
		public void read(JmeImporter im) throws IOException {
			for(B b:bList){ //Just trying to setup the existing objects with the saved data
				b.read(im);
			}
		}
	}
	
	static ArrayList<B> bList = new ArrayList<B>();
	public static class B implements Savable{
		@Override
		public void write(JmeExporter ex) throws IOException {
			OutputCapsule oc = ex.getCapsule(this);
			oc.write("tst1_"+hashCode(), "Test", "tst0"); //BREAKPOINT!
		}
		@Override
		public void read(JmeImporter im) throws IOException {
			InputCapsule ic = im.getCapsule(this); //BREAKPOINT!
			System.out.println("loaded: "+ic.readString("Test",null)); //crash :(
		}
	}
}

Alright, don’t call read() directly when reading a savable of type B you should do something like this:

B b = inputCapsule.readSavable("B", null);

But since you have a list of B you are not writing and reading it properly you should use writeSavableArrayList and readSavableArrayList:

public static class A implements Savable{
		@Override
		public void write(JmeExporter ex) throws IOException {
			OutputCapsule oc = ex.getCapsule(this);
                        oc.writeSavableArrayList(bList, "bList", null);
		}
		@Override
		public void read(JmeImporter im) throws IOException {
                        InputCapsule ic = im.getCapsule(this);
                        bList = ic.readSavableArrayList("bList', null);
		}
	}
1 Like

worked thx!

package tests;

import java.io.IOException;
import java.util.ArrayList;

import jme3tools.savegame.SaveGame;

import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.export.Savable;

public class SaveGameFailToLoad {
	public static void main(String[] args) {
		B b;
		b=new B("b1");b.strData="Look! :o" ;bList.add(b);
		b=new B("b2");b.strData="Where? oO";bList.add(b);
		
		SaveGame.saveGame(SaveGameFailToLoad.class.getSimpleName(), "TestSave", new A());
		for(B bZ:bList){bZ.strData="Zzzz";}
		SaveGame.loadGame(SaveGameFailToLoad.class.getSimpleName(), "TestSave");
	}
	
	/**
	 * A is just a concentrator of everything that should be saved.
	 */
	public static class A implements Savable{
		@Override
		public void write(JmeExporter ex) throws IOException {
			OutputCapsule oc = ex.getCapsule(this);
			oc.write(bList.toArray(new Savable[0]),"FieldListB",null);
			//for(B b:bList){oc.write(b, "FieldB:"+b.strName, null);} //so B becomes like fields of A
		}
		@Override
		public void read(JmeImporter im) throws IOException {
			InputCapsule ic = im.getCapsule(this);
			ic.readSavableArray("FieldListB",null);
			//for(B b:bList){ic.readSavable("FieldB:"+b.strName,null);}
		}
	}
	
	static ArrayList<B> bList = new ArrayList<B>();
	public static class B implements Savable{
		public B(){this.strName="forgotten";};
		public B(String strName){this.strName=strName;};
		private String strName;
		private String strData;
		@Override
		public void write(JmeExporter ex) throws IOException {
			OutputCapsule oc = ex.getCapsule(this);
			oc.write(strName, "FieldNameB", null); 
			oc.write(strData, "FieldDataB", null); 
		}
		@Override
		public void read(JmeImporter im) throws IOException {
			InputCapsule ic = im.getCapsule(this); //BREAKPOINT!
			for(B b:bList){ //Just trying to setup the existing objects with the saved data
				if(b.strName.equals(ic.readString("FieldNameB",null))){
					System.out.println("current: "+b);
					b.strData=ic.readString("FieldDataB",null);
					System.out.println("loaded:  "+b);
				}
			}
		}
		@Override
		public String toString() {
			StringBuilder builder = new StringBuilder();			builder.append("B [strName=");			builder.append(strName);			builder.append(", strData=");		builder.append(strData);			builder.append("]");
			return builder.toString();
		}
	}
}