How to save/load game data with Entity/Component based Engine via JSON

Hello dear JGO :slight_smile:

I am advancing with my project, which is a 2d Tile based game.
I use entities for pretty much everything, but i do not limit myself to just using entites with components over inheritance.

Furthermore, for the time beeing I do not use a fully fledged ECS, the way my system works for now is like this:

I store the entites in arrays (or wherever needed), and add components to the entity component hashMap.
The components the entity has, are described by the EnumSet of the enum type of the components.
Then i use systems which operate on the entity mask(EnumSet) and on the component values.

My question is: How could i save my entities, i.e the components instance variables, states etc. properly without having to add (at least not much) code,
when i add a new component types. Also, since itā€™s early development, i will change my component classes one day.

I guess i could add a method to every component, but thats something i would rather like to avoid, the less code -> the better!
Also i dont know how to structure this properly in JSON, and with structure i mean how the objects should be save in JSON in a certain hierarchy.

I tried saving some stuff yesterday and the more complex thing was to actually reload it without getting exceptions, since i would have to load everything as ā€˜JsonObjectā€™ and ā€˜JsonArrayā€™ etc. and then receive the correct values from it, then pass it to the class initialization.
That system seems extremely brittle to me and complete non-sense without a proper way of structuring it.

Thank you very much for your time and help in advance :slight_smile:

YOU DO NOT NEED TO READ THE CODE, IDEAS IN GENERAL ARE WELCOME, JUST FOR INFO

Entity Class example:


public class Entity {

	// IVARS
		// TAG
		private String tag = "none";
		// ENUM SET MASK
		private EnumSet<CompType>mask = null;
		// COMPONENT MAP
		private HashMap<CompType, Component>compMap = null;
	
	public Entity(){
		// INIT IVARS
			// INIT MASK WITH COM_TYPE 'NONE'
			this.mask = EnumSet.<CompType>of(CompType.NONE);
			// INIT COM_TYPE -> COMPONENT HASH MAP
			this.compMap = new HashMap<>(0);
	}
	
	public void addComponent(CompType compTypeIn, Component compInstIn){
		// ADD COMPONENT TO HASHMAP
		this.compMap.put(compTypeIn, compInstIn);
		// ADD COMP_TYPE TO MASK
		this.mask.add(compTypeIn);
	}
	
	public <T> T getComponent(CompType compTypeIn){
		return (T)(this.compMap.get(compTypeIn));
	}
	
	public void removeComponent(CompType compTypeIn){
		// REMOVE COMPONENT FROM HASHMAP
		this.compMap.remove(compTypeIn);
		// REMOVE COMP_TYPE FROM MASK
		this.mask.remove(compTypeIn);
	}
	
	// MASK GETTER
	public EnumSet<CompType> getMask(){return this.mask;}
	
	// TAG SETTER / GETTER
	public void setTag(String tagIn){this.tag = tagIn;}
	
	public String getTag(){return this.tag;}
	
}

Component Class example:


public class Transform_COMP extends Component{
	
        // IVARS
        public Vector2f pos = null;
        public Vector2f size = null;
        public float rotation = 0.0f;
	
        public Transform_COMP(float xIn, float yIn, float wIn, float hIn, float rotIn){

        // INIT IVARS
        this.pos = new Vector2f(xIn, yIn);
        this.size = new Vector2f(wIn, hIn);
        this.rotation = rotIn;	
	}
}

Forgive my ignorance here, but is there any reason you canā€™t just serialize your objects? Itā€™s probably not the greatest way to save things, but it sure is easy

FileOutputStream file_output_stream = new FileOutputStream(file_name);
			ObjectOutputStream obj_output_stream = new ObjectOutputStream(file_output_stream);
			obj_output_stream.writeObject(object);
			obj_output_stream.close();
			file_output_stream.close();

@thedanisaur

Hi thedanisaur :slight_smile:
You are right that it would be easy, but since i want to have some sort of ā€˜readableā€™ save files AND i do not want to fiddle around with my components instance variables.
Furthermore, i want to use something that is some kind of standard, and used crossplatform without a problem (allthough i dont know if serialization would be an issue).

I read a little about the serialization process, but for me thats too fiddly and as of what i understand of it atm, too much white ā€˜magicā€™ :slight_smile:

I used text files with tags that i split etc., but, atm i need something solid, without programming it all by myself (i tend to keep programming things that exist, and then loose time on my projectā€¦) that is also crossplatform.

And i want to get deeper into the techniques for saving stuff in general, which up to know, i didnt have to know anything about in gameprogramming, programming is a never ending tunnelā€¦ :slight_smile:

But thank you very much for the tip, some times obvious things are not so obvious :slight_smile:

Iā€™d recommend checking out existing JSON / Java serializers like Jackson or Boon. I havenā€™t worked with either of those libraries, so I donā€™t know how extensible they are or if you can replace how they might walk object graphs. I have no idea offhand if either of those would work out of the box and properly serialize an Entity or if youā€™ll have to provide bespoke serialization which means youā€™d have to manage the process. If the latter is the case perhaps you can make tag, mask, compMap package private and have a ā€œJsonEntityUtilā€ class in the same package that manages the serialization / deserialization which can directly access tag, mask, compMap.

Thank you very much for your suggestions, and sorry for answering so late.

I will have a look into these things :slight_smile: