Entitas
Entitas copied to clipboard
By using Entitas, is there a proper way to serialize a frame?
Hi,
As we all know that ECS makes data and behavior separated. So I wanna get a proper way to serialize all entities and their components (excluding rendering components). Given that a component is not supposed to present methods, how can I serialize them? It's useful to save a state and recover it at a later time.
Cheers
You can write a flag component like "RecordableComponent" and use JSON.net to serialize instances. However, I'm almost sure that this is not what you want by practice. For cool things like kill cam and rewindable gameplay, it's important to filter out unnecessary data, otherwise, the player's memory/harddisk would be blown up quickly because you're storing data at the 60Hz frequency.
So as you can see, it's not an Entitas related problem. IIRC, Zaks made a talk about how to implement a playback system, you can google that video, it's insightful.
You can write a flag component like "RecordableComponent" and use JSON.net to serialize instances. However, I'm almost sure that this is not what you want by practice. For cool things like kill cam and rewindable gameplay, it's important to filter out unnecessary data, otherwise, the player's memory/harddisk would be blown up quickly because you're storing data at the 60Hz frequency.
So as you can see, it's not an Entitas related problem. IIRC, Zaks made a talk about how to implement a playback system, you can google that video, it's insightful.
Thanks for your reply. It's really not an easy thing to do, I think so too. I found the following demo but, its solution so damn sucks if the systems grow more and more complex. https://github.com/coding2233/Entitas-Replay-Demo
I won't store the state data at every frame. Instead, I can save a state every 30 frames, and save the user-action every frame. What you said 'RecordableComponent' may be not enough, cause when I have collected all Recordable Entities, I still don't know what to record. I need manually organize all components I want to record in a recording-system. Maybe the best way is writing a code generator to automatically generate a component includes all components that have the attribute "Recordable".
Considering server/client communication, it's necessary to do serializing/deserializing. The code may look like
public RecordSystem(Contexts contexts)
{
_recordableEntities = contexts.game.GetGroup(GameMatcher.Recordable);
}
public void Execute()
{
Dictionary<int, byte[]> serialized = new Dictionary<int, byte[]>();
foreach (GameEntity e in _recordableEntities.GetEntities())
{
serialized[e.EntityId] = e.GetComponents<IRecordableComponent>().SerializeToBytes()
}
//do next...
}
JSON.Net needs more device resources, and bytes serialization such as protobuf breaks ECS rules.
I recorded and serialized the content data of the component. Next I wanna find a way to know what component the data belongs to.
public interface IRecordableComponent {}
[Game]
public class PositionComponent : IComponent, IRecordableComponent
{
public float x;
public float y;
}
[Game]
public class RecordableComponent : IComponent {}
public class RecordSystem : IExecuteSystem
{
readonly GameContext _context;
public RecordSystem(Contexts contexts)
{
_context = contexts.game;
}
public void Execute()
{
Dictionary<int, IComponent[]> entityData = new Dictionary<int, IComponent[]>();
var entities = _context.GetGroup(GameMatcher.Recordable);
foreach (var e in entities)
{
var comps = e.GetComponents().Where((c) => c is IRecordableComponent).ToArray();
entityData[e.creationIndex] = comps;
}
if (entityData.Count > 0)
{
Debug.Log(JsonConvert.SerializeObject(entityData));
}
}
}
If you are making a multiplayer game, don't use JSON, it's still too big unless your game is simple enough. We usually use a code generator to create contracts for State, Input and other stuff then serialize them as a dict/hashtable byte[]. Google GafferOnGames, there are lots of essential posts about networking on it and you will see how picky it is to transfer data in a real game. In short, every bit you saved is $$$ :wink:
If you are making a multiplayer game, don't use JSON, it's still too big unless your game is simple enough. We usually use code generator to create contracts for State, Input and other stuff then serialize them as a dict/hashtable byte[]. Google GafferOnGames, there are lots of network essential posts on it and you will see how picky it is to transfer data in a real game. In short, every bit you saved is $$$ 😉
You are so cool!