The problem you encountered is that you seem to have no clear way of serialising/unserialising your entities.
You can keep your create<EntityType>()
functions to create initial versions of your entities, but you should be able to serialise the entities. And unserialising them should result in the same result as what was there before the serialisation process.
When you write an entity (to file or network stream) the resulting data should allow you to reverse the process and unserialise just as easily:
Serialized entity:
{
'id':38,
'transform':{'x': 300, 'y': 40, 'angle':0, scale:1},
'movement':{'id':'walk', 'maxspeed': 30, 'turnrate': 180},
'movement':{'id':'flight', 'maxspeed': 180, 'turnrate': 20},
'weapon':{'id':'claws', 'dmg':[{'slash':300}], 'rate':0.25},
'weapon':{'id':'firebreath', 'dmg':[{'fire':30}], 'rate':5, 'remaining':58, 'rr':2},
'visual':{'model':'dragon_02', 'mainColor':'FF4921'},
'dragonScript'{'anger':12.333333,},
'health':{'hp':2004, 'hr':3},
'intent':{script:[
{'id':'move', 'movement':'walk', 'data':[1,0]},
{'id':'fire', 'weapon':'firebreath'}]}
}
Here we can clearly rebuild the entity with an id, and all the components needed for the game to resume/start.
There are certain components you will want to avoid serialising (i.e. all components related to local behaviours like input or data which should be recomputed from the existing data).
But in the end a simple function to reload all components should do the trick:
Ex:
unserializeEntity(pojo) {
var entity = null;
var cmps = [];
//Each key could be used to code the type of component...
for(var componentType in pojo) {
var cmp = createComponent(componentType, pojo[componentType]);
if(cmp) {
cmps.push(cmp);
}
}
if (0 < cmps.length) {
entity = new Entity(pogo.id);
entity.addComponents(cmps);
}
return entity;
}
//Once all entities are unserialised simply add them to your engine
for(...) { engine.add(entities[i]); }
// once all entities have been unserialised and added you can wake them up
//so they can recompute all the missing data and fetch dependencies
for(...) { entities[i].awake(); }
If this approach doesn't allow you to retrieve all the behaviours and data needed for your entities then you might have to rethink your design if you want to be able to pass arbitrary entities across the network.
Edit: To avoid sending too much data try to compress it. For example using http compression if you send the data to a browser.
Otherwise you can use any other compression library available to you. lz4 is a good one, it has a browser implementation as well as a native one for node.
Using the above dragon entity I get the following result after using lz4:
data.length:1200 compressed.length:444
Quite good and it also saves space when writing to files or database.