outfox / fennecs

... the tiny C# ECS that loves you back!
https://fennecs.tech
MIT License
223 stars 10 forks source link

Archetypes with Self-Referencing Relation in Signature can't Despawn referenced Entity #17

Closed thygrrr closed 3 months ago

thygrrr commented 5 months ago

What:

The order of operations for one or more entities despawning from an archetype where one or more of the Relations target that Entity itself causes an unhandled exception.

Repro:

Crashes on all runs.

    [Theory]
    [InlineData(1)]
    [InlineData(2)]
    [InlineData(3)]
    [InlineData(10)]
    [InlineData(69)]
    [InlineData(200)]
    public void DespawningBulkInSelfReferencedArchetypeIsPossible(int relations)
    {
        using var world = new World();

        var subjects = new List<Entity>();
        var rnd = new Random(1234 + relations);

        for (var i = 0; i < relations; i++)
        {
            subjects.Add(world.Spawn());
        }

        // Create a bunch of self-referential relations
        foreach (var subject in subjects)
        {
            subject.Add(rnd.Next(), subject);
        }

        var query = world.Query<int>(Match.Entity).Compile();
        Assert.Equal(relations, query.Count);

        query.Truncate(relations/2);

        Assert.Equal(relations/2, query.Count);
    }

Crashes on Runs greater than 1:

    [Theory]
    [InlineData(1)]
    [InlineData(2)]
    [InlineData(3)]
    [InlineData(10)]
    [InlineData(69)]
    [InlineData(200)]
    public void DespawningSingleInSelfReferencedArchetypeIsPossible(int relations)
    {
        using var world = new World();

        var subjects = new List<Entity>();
        var rnd = new Random(1234 + relations);

        for (var i = 0; i < relations; i++)
        {
            subjects.Add(world.Spawn());
        }

        // Create a bunch of self-referential relations
        foreach (var subject in subjects)
        {
            subject.Add(rnd.Next(), subject);
        }

        var query = world.Query<int>(Match.Entity).Compile();
        Assert.Equal(relations, query.Count);

        // Create a bunch of self-referential relations
        foreach (var subject in subjects)
        {
            subject.Despawn();
        }

        Assert.Equal(relations/2, query.Count);
    }

Potential Fix:

Difficult to fix heuristically, but: