Entt: How to simply clone an entire registry?

Created on 17 Aug 2020  路  13Comments  路  Source: skypjack/entt

With clone() removed earlier this year, it's unclear what is the intended way to simply, completely clone a registry, all entities and components. Based on the example in the wiki, use of visit() is part of the long term plan, but currently to do anything with the id types it provides you need to in some way declare what component types you're using. I'm looking for a solution that doesn't require knowing the component types.

question

Most helpful comment

More than likely, but I also don't want to optimize prematurely. And it'll be difficult to make those decisions or design specialized serialization when I'm still familiarizing myself with how to use ECS, and haven't even decided what kind of game I'm making.

All 13 comments

I'm working to reintroduce clone as well as stamp but in a way such that users won't pay for them if they aren't interested in using these feature.
In the meantime, even though cloning a whole registry is somewhat discouraged, it offers all the functionalities to do that already.
As for the last request, you can use a reflection system to do that if you don't want to list all types.

Alright. What syntax would you suggest for doing that? Do I need to make any special consideration to preserve entity ids and destroyed entities?

What syntax would you suggest for doing that?

Doing _that_... what? Cloning the registry and the pools that matter? You can use the range functionalities for that.
There is all you need to clone entities (assign) and components (emplace) from a bunch of iterators (those returned by views, groups or registry::data/registry::raw.
Let me know if something is unclear. I'm a little in a rush today but I can provide an example tomorrow if needed.

Okay, I think I have entities worked out with assign() and data().

By that I meant how do I use reflection to copy components without specifying their types?
For example, assuming registry::raw<Component>() is what I want to use, I don't know how to invoke that while iterating component types with visit().
So how would I do that? Is that the best way to go about it in the current version? Do I have to register the types beforehand like the example in the wiki, or can I avoid that?

You should register meta functions for that, something like:

entt::meta<T>().func<&clone<T>>("clone");

Where clone is defined as:

template<typename T>
void clone(entt::registry &src, entt::registry &dst) {
    auto view = src.view<T>();
    dst.emplace(view.data(), view.data() + view.size(), view.raw(), view.raw() + view.size());
}

Then:

src.visit([&dst](auto component) { entt::resolve_id(component).func("clone").invoke({}, std::ref(src), std::ref(dst)); }

Everything out of my mind, so it may contain errors.
For a future release, the idea is to make this transparent and easier to wire up, use, whatever.

In terms of errors, clone would be something like

void clone(entt::registry& src, entt::registry& dst)
{
    auto view = src.view<T>();
    if constexpr (ENTT_IS_EMPTY(T)) {
        dst.insert<T>(view.data(), view.data() + view.size());
    }
    else {
        dst.insert<T>(view.data(), view.data() + view.size(), view.raw(), view.raw() + view.size());
    }
}

Though I can't get the rest of the example working because I can't get resolve_id nor resolve_type to work.

However, I'm looking for a solution that doesn't involve ever explicitly registering or listing the specific types I'm using for components. I'd like to clone a registry regardless of what's in it.
For myself I'm going to try reverting b5e411d251e334a7b050a504bb47a10680f56987 on my fork and just use the old clone functionality, but it'd be useful to have a convenient alternative in the current version until the future release where it can be easily automated with meta.

Out of curiosity, what's the use case for cloning a registry as a whole?
I do this but only for some pools, so as to _offline_ computations. I have never had the necessity of cloning everything so far.

As I believe some other users have attempted based on the wording of their issues, I want to use an ECS game state with speculative rollback netcode.
The first core requirement of rollback is that the game state can be serialized or cloned, so that whenever the input prediction on speculative frames is wrong the last correct state can be restored, and that simulation can continue from there with the corrected inputs.
(See pond3r/ggpo if you're unfamiliar with the framework and want to read more)

Ok, in this case I wouldn't serialize everything though. For example, components that contain handles to resources.
Put aside the serialization process, the less you serialize, the better. Serializing a _state_ for this purpose is better achieved by manipulating the components and transforming them in a form that is less demanding.

More than likely, but I also don't want to optimize prematurely. And it'll be difficult to make those decisions or design specialized serialization when I'm still familiarizing myself with how to use ECS, and haven't even decided what kind of game I'm making.

Alright, think I got it reverted onto the current master without issue (639b1ec if anyone is interested; had to make adjustments to account for renamed and modified functions).
Still not sure why resolve_id() and resolve_type() weren't working for me, but for now I don't need them. Will be looking forward to the future updates that make clone truly obsolete.

EDIT: welp looks like I messed something up so time to keep working on it

I'm closing this since the question has been asnwered and there is already a plan to get around what you did.
Thanks for discussing your issue and providing more details for future users.

Fixed the bugs I had with re-adding clone (d50d3e8). The unit tests proved quite helpful.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

markand picture markand  路  5Comments

Kerndog73 picture Kerndog73  路  5Comments

Milerius picture Milerius  路  5Comments

Deins picture Deins  路  6Comments

blockspacer picture blockspacer  路  3Comments