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

Make EntityCommandRecorder support new world #143

Open
darl2ng opened this issue Nov 26, 2021 · 3 comments
Open

Make EntityCommandRecorder support new world #143

darl2ng opened this issue Nov 26, 2021 · 3 comments

Comments

@darl2ng
Copy link

darl2ng commented Nov 26, 2021

Also in the synchronization of multiple world context, currently I have to copy one entity from one world to another in order to replay it with the recorder.

It would be nice to make the recorder aware of the world it should replay (override it) to avoid additional copy.

Thanks!

@darl2ng
Copy link
Author

darl2ng commented Nov 29, 2021

Speaking of wishes :-) it would be "so great" to be able to serialize and then de-serialize the recorder content (of course with some kind of hook that does not impact the performance)

@Doraku
Copy link
Owner

Doraku commented Nov 29, 2021

I am curious for the reason you need to constantly synchronise entities from different worlds. When I designed the CopyTo method, what I had in mind was to transfer only some entities to a different world when you change level, stuff like that. So the player entities and state is transferred as you load new levels in new worlds which only occurs once in a while.

Some times ago the recorder would actually take a world parameter in the Execute method but it would only be used for the recorded creation of entities so it made more sens to introduce a WorldRecord in case you wanted to record actions from multiple worlds at the same time. Trying to override the internal world id of all recorded entity so that when replayed it will do the same operations on "synchronized" entities that just happen to have the same internal ids in both worlds seems like a dangerous hack that can blow up at any moment ^^"

it would be "so great" to be able to serialize and then de-serialize the recorder content

ha I actually intended to do that when I created the recorder (that's why internally there is an Executer instead of having the code directly in EntityCommandRecorder, I wanted to create some kind of factory that could be serialized). After some thinking I came to the realization that if I needed a serializable factory, it would be easier to just code the method directly, or create simples types to do just that (this is what I have in my game for example):

    public interface IEntityAction
    {
        void Execute(in Entity entity);
    }

    public sealed class SetEntityAction<T> : IEntityAction
    {
        private readonly T _value;

        public SetEntityAction(T value)
        {
            _value = value;
        }

        void IEntityAction.Execute(in Entity entity) => entity.Set(_value);
    }

    public sealed class LightSetEntityAction<T> : IEntityAction
    {
        private readonly T _value;

        public LightSetEntityAction(T value)
        {
            _value = value;
        }

        void IEntityAction.Execute(in Entity entity) => entity.Get<T>() = _value;
    }

    public sealed class RemoveEntityAction<T> : IEntityAction
    {
        void IEntityAction.Execute(in Entity entity) => entity.Remove<T>();
    }

    public sealed class EnableEntityAction<T> : IEntityAction
    {
        void IEntityAction.Execute(in Entity entity) => entity.Enable<T>();
    }

    public sealed class DisableEntityAction<T> : IEntityAction
    {
        void IEntityAction.Execute(in Entity entity) => entity.Disable<T>();
    }

    public sealed class EnableEntityAction : IEntityAction
    {
        void IEntityAction.Execute(in Entity entity) => entity.Enable();
    }

    public sealed class DisableEntityAction : IEntityAction
    {
        void IEntityAction.Execute(in Entity entity) => entity.Disable();
    }

    public sealed class EntityFactory
    {
        private readonly IEntityAction[] _actions;

        public EntityFactory(params IEntityAction[] actions)
        {
            _actions = actions;
        }

        public void Execute(in Entity entity)
        {
            foreach (IEntityAction action in _actions)
            {
                action.Execute(entity);
            }
        }

        public Entity Execute(World world)
        {
            Entity entity = world.CreateEntity();

            Execute(entity);

            return entity;
        }
    }

I can create a EntityFactory in my game data editor and serialize it, then deserialize the factory to use it in my game.

@darl2ng
Copy link
Author

darl2ng commented Nov 30, 2021

I am curious for the reason you need to constantly synchronise entities from different worlds. When I designed the CopyTo method, what I had in mind was to transfer only some entities to a different world when you change level, stuff like that. So the player entities and state is transferred as you load new levels in new worlds which only occurs once in a while.

I see many use cases for that, a replicated world for spectator mode come to mind first, but you can do 2-way sync for multi-player games, too.

Some times ago the recorder would actually take a world parameter in the Execute method but it would only be used for the recorded creation of entities so it made more sens to introduce a WorldRecord in case you wanted to record actions from multiple worlds at the same time. Trying to override the internal world id of all recorded entity so that when replayed it will do the same operations on "synchronized" entities that just happen to have the same internal ids in both worlds seems like a dangerous hack that can blow up at any moment ^^"

It is a runtime database with entity id, component id and value objects so it should be fine ^^

ha I actually intended to do that when I created the recorder (that's why internally there is an Executer instead of having the code directly in EntityCommandRecorder, I wanted to create some kind of factory that could be serialized). After some thinking I came to the realization that if I needed a serializable factory, it would be easier to just code the method directly, or create simples types to do just that (this is what I have in my game for example):

I really like the idea because normal serialization/de-serialization only handles the creation/addition of entities/components, while the recorder handles that, and more, with deletion/remove/update of entities/components. Why not using the same "back end" implementation I told myself ^^. Of course, we can implement both features at a higher level as usual, separately.

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