Skip to content

Inconsistent Migrate/Batch operation when new Archetypes are created during World.Catchup #42

Description

@thygrrr

This (likely) outputs:
false
true
true
true

User likely expects true all around.

struct ComponentA;
struct ComponentB;

static void Test(World world)
{
    for (var i = 0; i < 2; i++)
    {
        var e = world.Spawn()
            .Add<ComponentA>()
            .Add<ComponentB>();

        using (world.Lock())
        {
            world.Stream<ComponentA>()
                .For((in entity, ref _) => entity.Remove<ComponentA>());

            world.Stream<ComponentB>()
                .Query
                .Batch()
                .Remove<ComponentB>()
                .Submit();
        }

        Console.WriteLine(e.Has<ComponentA>()); // false
        Console.WriteLine(e.Has<ComponentB>()); // true
    }
}

Theory - not a bug, but a footgun and might need some architectural rework.
What happens is that the batch takes note of the archetypes, not the entities.

When you create the entity, there are 2 archetypes: A (Has)first, and then it's directly moved into AB. Query matches archetype AB.

After the Query1's Stream.For has pushed all the commands, none are executed yet. Stream.Batch takes note to remove B from all current archetypes in Query 2, which is at that time only AB.

Then at end of scope, the commands are caught up (processed) in order, and before the batch command, AB is completely empty (all entities were moved into new 3rd archetype B, which the query and batch didn't know about at the time).
Maybe I want to change it so not the archetypes, but the query is noted with each batch.
But there are other things - e.g. when adding components - where this behaviour might then be surprising. (maybe... lots of maybes)
If the lock weren't there, then when the Stream.For has finished, all changes are caught up and the batch would operate on a query that knows the old AB and the newly created B archetype.
If the order were reversed, then everything is moved into archetype A, but Query 1 doesn't care about that because it notes down commands directly for the entities, and for them "remove" is still legal.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementImprovement on existing implementation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions