-
Notifications
You must be signed in to change notification settings - Fork 144
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
Persisting/serializing entities #220
Comments
Since entities are not represent whole application state, persisting them is only part of whole app state persistence. Withal systems' internal state, it could be not possible to perform such universal (de)serialization. So I think it's kind of beyond ECS and rather specific case that's why should be handled outside. |
In my experience, typical usage is to save a subset of entities.
One usually wants to serialize most component types - better to opt-out with an annotation (I'm fond of Dealing with components with fields referencing other entities was one of the bigger hurdles - these relationships must be persisted and properly restored at load. GWT support is even trickier, but doable - usual GWT procedures apply.
As an option, it's probably a good idea - as long as there's a default case which just works.
One can certainly model it in such a way that entities+components are all the state. We have 70+ systems, ~50 component types, spread out over a number iof world/engines - without using any custom de/serialization code. We're also using the same save/load mechanism for "prefabs" (entity blob with some user-defined logic). |
@junkdog I agree with pretty much what you say. Occasionally, you want custom serialization/deserialization logic eg. component that holds a reference to a I'm unsure whether I would like to maintain such system inside Ashley as it's tricky to find a silver bullet. It would certainly help if we provided a suggested approach on the wiki. |
@junkdog @saltares As you said it hasn't to be maintained inside Ashley. But it would certainly be nice if others can benefit from it too. Having something in the wiki and code in some other repository seems like reasonable/good idea. Nested entities are the biggest hurdle I think. But depending on what libraries are used it could be handled very easily. |
As long as the underlying serialization framework exposes a means of supplying serializers, or maybe put an interface on the component, it shouldn't be a problem.
Hmm, what we do is that we have serializable "asset reference" components that go with each unserializable component type (FontReference->FontRenderable, SpineReference->SpineRenderable etc). For each pair, we have a "reactive"/resolver system creating the actual asset - eg, This soulotion ends up looking pretty clean - one resolver system per asset type - plus, it saves us from writing custom serialization logic.
There's some custom serialization logic to cope with ashley's internal state - and the serialization code needs to internally track entity relationships when saving/loading, otherwise this won't work: public class InheritScale implements Component {
public Entity target;
} imo, gson is a bit bloated compared to libgdx's json API. it's one dependency less, too. |
Using Libgdx's Json API sounds like the natural thing to do since we're already depending on it. Would this work?
I'd prefer not to add serialization logic to I think this supports @junkdog's and @meisterfuu's observations.
If we make
What do you prefer? |
Valid point. I like the first idea more. It gives more controll and one could do something like this :
Then the entity can added to an exisiting engine. And it is possible to persist&load only a subset of entities. And it makes it more clear what is going on. |
Actually I missed a couple points @junkdog made. Which entities to serialize?We may not want to save all entities, an Do we want to have a Serializing systems?Do we wan to serialize system's state? Ideally, systems should be stateless but people may rely on system's state and may need to persist that too. PoolsWe also need to provide a solution for So my previous idea could fall a little short on this, but it could be on the right direction. |
And, per default - implementing
I've never done it myself, but I do think there are valid, perhaps situational, use-cases for wanting to serialize state not directly bound to entities:
Another good-to-have feature is support for tagging serialized entities with a key. With tags, building prefab-like classes is straight forward: load from json, then retrieve the needed entities and update as required. |
Thank you guys for the great feedback and the discussion. I'm going to have a go at it, write some unit tests and possibly push it to a branch in this repo and ask for some more feedback then. |
@junkdog how do you see that working? how would you tag entity configurations, specifically? |
We have a SerializationTag component (not to be confused with some global tag id). When loading, the object wrapping the entities also builds key:entity lookup map. I'll see if I can dig up some code which better shows what I mean. |
Writing an Any ideas to decouple these? |
We might not need to decouple these. Probably just implement a That way no matter of the Engine type the creation of the Entity ist the same (Maybe do the same for Components) |
That would mean the |
Giving the |
@meisterfuu, @metaphore, @junkdog and @laubed, could you please take a look at the serialization branch? It's simpler now and it includes an The tests should make the serialization API self explanatory although I'm happy to answer any questions. I definitely accept suggestions to make it better. Thanks a lot! |
I took a quick look. I like the design, very clean. There should probably be a way to load multiple entities at once, without spawning a new engine. Full What about persisting entity references in component fields - are those planned for the first release? |
I agree with @junkdog . But I think handling references in general would be better placed in the json library. Enables multiple components sharing the same objects(not only entities) in a field. (e.g. two players having the same inventory). But I don't know much about the libgdx json classes.(Only used them rarely) I will do some tests with the current branch later and see how well it integrates with an existing prototype. |
Thanks for the feedback guys.
You can take a JSON array and call
Maybe have custom component |
I think many projects gravitate towards more complicated multi-entity compositions. (do we have a term for these, I usually call entities spanning multiple entities for "conceptual entity", but not the best term). In those situations, only loading a single entity at a time may require a lot of manual wiring, and extra overhead.
We resolve entity references automatically. This helps greatly when dealing with conceptual entities spanning multiple entities. If the serializer ensures entity relationship integrity, one can build pretty sophisticated entity templates with ease.
Couldn't it be internal to the main serializer - if only allowing plain |
Will there be any further improvement on this branch ? That would be such an interesting feature to be found in the master ! |
I know! I'm finding it hard to find the time. I would really appreciate some help on this. |
I'm a bit late into this discussion and haven't read everything here, but I would not serialize the entity system, I would have a model with the whole structure that I can serialize and when building the Engine passing the objects from this model to the entities/systems so that all updates change the objects in the model... works great :) |
Please don't use libgdx's json or xml libraries. There faster and more maintained libraries out there doing a better job, and aside from that, the biggest problem with libgdx's approach is, that it stores the classpath of each class in the json/xml, which bloats the filesize and also makes it really difficult to refactor code. |
@Lusito libgdx's json/xml libraries allow you to customize classTag. IMO these libraries are well maintained. And I didn't noticed performences issues serializing hundreads of entities unless you have some benchmarks about it ... which alternatives would you suggest ? |
@mgsx-dev It's a very hidden option and it doesn't seem to be the recommended way looking at the tutorials. Even the libgdx 3D Particle Editor "Flame" does not make use of the classTag feature. And looking at this file, I know enough about libgdx's way of conforming to standards: For json, gson is a good start and for xml xstream is a nice choice. They have proven time and again to be fast (especially with big files), stable and conforming to standards. |
@Lusito To be honest I was thinking exactly the same as you few times ago :D but this weird json format appear to me to be very handy actually but it's just a question of taste and you can use both strong or simple format. Anyway, IMO matter here is not which serializer to use (it could be abstracted by the API, letting client code make his choice), matter is more on subject like "how to serialize entities cross references", "how to serialize systems", "which entities to save", "which components to save" .... I'm working on it in one of my project and technical serialization is maybe the less important issues I had so far. |
I am currently looking into a good way to persist all my entities. The main use case is saving&loading the game.
Now I could iterate over every entity and check for every possible component and store everything in some way. Then on loading I would have to reverse this process.
But at the very best I don't want to do this too "game specific" and would prefer a more generic way of doing this that other people can benefit from. (That also works with a pooled engine and hopefully on all plattforms too!)
At the end I want something like this:
I think it would be good if one could mark every component that should be persisted with an annotation and/or interface and exclude fields with transient or an annotation. (e.g. a SpriteComponent with TextureRegions)
Maybe allow the components to handle the serialization by itself. (onSave, onLoad - similar to the android bundle concept))
I hope I get some input on this. And I intend to contribute this to Ashley or the community in some way.
The text was updated successfully, but these errors were encountered: