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

Debug.Assert for operations on entities and dead entities. #110

Open
k-u-s opened this issue May 10, 2023 · 2 comments
Open

Debug.Assert for operations on entities and dead entities. #110

k-u-s opened this issue May 10, 2023 · 2 comments
Labels
enhancement New feature or request

Comments

@k-u-s
Copy link

k-u-s commented May 10, 2023

Encountered another issue when investigating #109

using Arch.Core.CommandBuffer;
using Arch.Core.Utils;
using Arch.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Arch.Core.Extensions;

namespace ConsoleTestApp;

internal class ArchDuplicatedResults
{
    private static int _index;
    private static World _world;
    private static QueryDescription _queryDesc;
    private static QueryDescription _queryDesc1;
    private static QueryDescription _queryDesc2;

    public static void Execute()
    {
        _world = World.Create();
        _queryDesc = new QueryDescription().WithAll<Base, Component1>();
        _queryDesc1 = new QueryDescription().WithAll<Component2>();
        _queryDesc2 = new QueryDescription().WithAll<Component3>();

        var list = new List<All>();
        for(var i = 0; i < 100; i++)
            list.Add(SpawnEntity());

        var res1 = CheckQuery();
        if (res1 != 100)
            Console.WriteLine("hmm1");

        for (var i = 0; i < 100; i += 10)
            list[i].Base.Ref.Entity.Remove<Component2>();

        var res2 = CheckQuery();
        if (res2 != 100)
            Console.WriteLine("hmm2");

        for (var i = 0; i < 100; i += 10)
            _world.Destroy(list[i].Base.Ref.Entity);

        var res3 = CheckQuery();
        if (res3 != 90)
            Console.WriteLine("hmm3");

        for (var i = 0; i < 100; i += 10)
        {
            var cur = list[i];
            var c3 = new Component3() { Val = cur.Component1.Val };
            cur.Component3 = c3;
            _world.Add(cur.Base.Ref.Entity, in c3);
        }

        var res4 = CheckQuery();
        if (res4 != 90)
            Console.WriteLine("hmm4");

    }

    private static int CheckQuery()
    {
        var queryRes = new List<(Arch.Core.EntityReference, Base, Component1)>();
        var query = _world.Query(in _queryDesc);
        foreach (ref var chunk in query)
        foreach (var index in chunk)
        {
            ref readonly var e = ref chunk.Entity(index);
            if (!e.IsAlive())
                continue;

            if (!e.Has<Base, Component1>())
                continue;

            var refs = e.Get<Base, Component1>();
            queryRes.Add((e.Reference(), refs.t0, refs.t1));
        }

        foreach (var (entityReference, entity, component) in queryRes)
        {
            if (entityReference.Entity.Id != entity.Ref.Entity.Id)
            {
                Console.WriteLine("Hmm");
                continue;
            }

            
        }

        return queryRes.Count;
    }

    private static All SpawnEntity()
    {
        var e = _world.Create();
        var entityRef = e.Reference();
        var index = ++_index;
        var b = new Base() { Ref = entityRef };
        var c1 = new Component1() { Val = index };
        var c2 = new Component2() { Val = index.ToString() };
        _world.Add(e, in b);
        _world.Add(e, in c1);
        _world.Add(e, in c2);

        return new All
        {
            Base = b,
            Component1 = c1,
            Component2 = c2
        };
    }

    class All
    {
        public Base Base { get; init; }
        public Component1 Component1 { get; set; }
        public Component2 Component2 { get; set; }
        public Component3 Component3 { get; set; }
    }

    class Base
    {
        public EntityReference Ref { get; init; }
    }

    class Component1
    {
        public int Val { get; set; }
    }

    class Component2
    {
        public string Val { get; set; }
    }

    class Component3
    {
        public double Val { get; set; }
    }
}

Runing ArchDuplicatedResults.Execute() produced null ptr ex in line _world.Add(cur.Base.Ref.Entity, in c3);

image

@k-u-s
Copy link
Author

k-u-s commented May 10, 2023

I assume that because give Entity was destroyed before.

So behavior is ok just Error could give more details cause NulltPtr looks like unhandled situation

@genaray genaray changed the title NullReferenceException during adding component Debug.Assert for operations on dead entities. May 10, 2023
@genaray genaray added the enhancement New feature or request label May 10, 2023
@genaray
Copy link
Owner

genaray commented May 10, 2023

I assume that because give Entity was destroyed before.

So behavior is ok just Error could give more details cause NulltPtr looks like unhandled situation

Yep, operations on dead entities can result in such exceptions.
I will add Debug.Asserts to inform the user that the operation is not valid since the entity is dead.

@genaray genaray changed the title Debug.Assert for operations on dead entities. Debug.Assert for operations on entities and dead entities. May 11, 2023
@genaray genaray moved this to Todo in Arch Roadmap Aug 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Todo
Development

No branches or pull requests

2 participants