Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

serialization #117

Closed
dendryte opened this issue Dec 20, 2015 · 5 comments
Closed

serialization #117

dendryte opened this issue Dec 20, 2015 · 5 comments

Comments

@dendryte
Copy link

How would I do serialization using entityx? I thought of 2 possible approaches:

  1. Attempt to save the state of the entityx::entityx class. I'm not sure how complex that'll be, and I'm relatively new to c++ template programming; so the templates and such look intimidating.
  2. create a separate entity class, which contains a bit field indicating which components that entity has, followed by a variable corresponding to each component I have. Then serialization would be checking if the entity has each component and if so, storing it in the corresponding variable. Deserialization is checking if that component exists, and adding it to the entity. This sounds really inefficient and painful though, and won't work for cases like components referencing entities.

Has anyone attempted the first approach?

@alecthomas
Copy link
Owner

This has been discussed before. Have a read of that for a fairly complete solution.

To summarise: internally, EntityX has no concept of the types of its components, so you'll have to use one if(entity.has_component<C>()) statement per component to check if an entity has that component, then serialise however you prefer.

As an aside, this is "solved" in the experimental/compile_time branch. The EntityManager in that branch is aware of all of its contained component types at compile time, so it could be made to serialize fairly easily.

@dendryte
Copy link
Author

I did manage to get the experimental compile-time branch working, kind of. I used boost.serialization to copy the raw memory inside storage as a binary object. Problem is that it isn't actually aware of the type of the object, so it works with things like integers but fails to work with complex types. So the only way to do it is to use the public APIs to add components.

Can you provide an overview of what I'd need to do to implement proper serialization for the experimental/compile-time branch, and what sort of template programming features I'd need to learn to do so? What would be the best way to store the "types" of components an entity has, so that you can add new component types without breaking compatibility?

@alecthomas
Copy link
Owner

Sure. You need to look at variadic templates, in particular recursive iteration over types. The Components<> template shows examples of this (eg. destroy). It should be possible to add an each() method to iterate over components, and call serialize/deserialize methods.

@dendryte
Copy link
Author

Thanks for the references; I'll check them out. Hmm, if I manage to figure that out, the last pieces of the puzzle are encoding the components an entities has, and when loading, to use that info to load just the components necessary. I can't think of any way of doing that though without going back to square 1; a long if statement.

@dendryte
Copy link
Author

I think I've figured out a relatively painless way of doing serialization using variadic templates. The idea is this:

Serialization:

  • get a count of the number of entities you want to save, and save that to the archive
  • create an ordered list of the component types present on an entity. e.g, "position", "velocity". Save this to the archive.
  • based on the components present, call an instance of a function template that saves that component to the archive.

Deserialization is the reverse

Implementation:
I found a useful library, boost.type_index, that can obtain the string name of a type at compile time.
For example, Velocity is a struct. boost::typeindex::type_id().pretty_name() returns "struct Velocity".

  1. Specify all the types of components that are being used at compile time. e.g
    Level<Position, Velocity, ...>
  2. Implement 2 function templates for saving and loading.
    a) one that saves any type of component an entity has to the archive
    b) one that loads an arbitrary component from the archive, and adds it to an entity
  3. Create 2 maps between the string name of the component's type from boost.type_index to instances of the template function that saves and loads that component. A variadic template can be used to do this automatically.
  4. create a variadic template, getComponentsForEntity, that checks whether an entity has all the possible component types (i.e, position, velocity etc). If so, it adds the boost::type_index for that type to a set and return it.

When saving, run getComponentsForEntity to generate the list. The strings in the list are then indices to function pointers that can be used to invoke the appropriate save and load functions without manual if statements.

Hope this helps anyone else who may be wanting to do serialization.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants