Skip to content

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

@thygrrr

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementImprovement on existing implementation

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions