SanderMertens / flecs

A fast entity component system (ECS) for C & C++

Home Page:https://www.flecs.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

INTERNAL_ERROR when call children()

Esp9527 opened this issue · comments

Describe the bug
v3.2.9

To Reproduce
Steps to reproduce the behavior:
`

#include <flecs.h>
#include <vector>
#include <iostream>

struct Player {
    int id;
};

struct Monster {
    int id;
};

struct Attack {
    int id;
};

struct Buffer {
    int id;
};

struct Cast{};
struct Died{};

struct Prefabs{
    struct Player{};
    struct Monster{};
    struct Buffer{};
    struct Attack{};
};

int main(int, char *[]) {
    flecs::world world;
    world.component<Monster>();
    world.component<Player>();
    world.component<Attack>();
    world.component<Died>();

    world.prefab<Prefabs::Player>()
        .override<Player>();

    world.prefab<Prefabs::Attack>()
            .override<Attack>();
    world.prefab<Prefabs::Monster>()
            .override<Monster>();
    world.prefab<Prefabs::Buffer>()
            .override<Buffer>();

    auto player = world.entity().is_a<Prefabs::Player>();
    auto monster = world.entity().is_a<Prefabs::Monster>();
    flecs::entity attack, buffer;

    world.system<Player>("System-Player")
        .each([&attack](flecs::entity e, Player& p){
            if(attack) return;

            std::cout << " System-Player-Run " << std::endl;
            auto world = e.world();
            auto attack = world.entity().is_a<Prefabs::Attack>().child_of(e);
//            attack.set<Attack>({});
        });

    world.system<Attack>("System-Attack")
        .each([&buffer, &monster](flecs::entity e, Attack& a){
            if(buffer) return;

            std::cout << " System-Attack-Run " << std::endl;
            auto world = e.world();
            buffer = world.entity().is_a<Prefabs::Buffer>().child_of(monster);
            monster.add<Died>();
        });

    world.observer<>("Observer-Died")
        .term<Died>()
        .event(flecs::OnSet)
        .each([](flecs::entity e){
            std::cout << " Observer-Died-Run " << std::endl;
            e.children([](flecs::entity c){});
        });

    ecs_log_set_level(3);
    world.app().target_fps(20).run();
    return 0;
}

`
Expected behavior
0>player,monster,attack,buffer is prefabs
1>create a player , monster
2>player create a attack
3>attack create a buffer (child of monster), and monster add died
4> monster observer died, and call children (crash)

will print fatal: observable.c: 1002: assert: r->table == elem->table INTERNAL_ERROR

`

        // flecs_emit_forward
        ecs_record_t *r = elem->record;

        ecs_assert(rc_idr->id == elem->id, ECS_INTERNAL_ERROR, NULL);
        ecs_assert(r != NULL, ECS_INTERNAL_ERROR, NULL);
        ecs_assert(flecs_entities_get(world, elem->src) == r,
            ECS_INTERNAL_ERROR, NULL);

        ecs_dbg_assert(r->table == elem->table, ECS_INTERNAL_ERROR, NULL);

        int32_t offset = ECS_RECORD_TO_ROW(r->row);
        flecs_emit_forward_id(world, er, er_onset, emit_ids, it, table,
            rc_idr, elem->src, r->table, tr->index, offset, trav, evtx);

`
fatal: observable.c: 1002: assert: r->table == elem->table INTERNAL_ERROR

Additional context
Add any other context about the problem here (operating system, hardware, ...).

Yup that's a bug! Looking into it.

Was able to reduce the reproducer to:

#include <flecs.h>

struct Foo{};

int main(int, char *[]) {
    flecs::world world;

    world.component<Foo>();

    world.observer<>()
        .term<Foo>()
        .event(flecs::OnAdd)
        .each([](flecs::entity e){
            e.children([](flecs::entity c){});
        });

    flecs::entity p1 = world.entity();
    flecs::entity e1 = world.entity().is_a(p1);

    world.defer_begin();
    world.entity().is_a(p1).child_of(e1);
    e1.add<Foo>();
    world.defer_end();

    return 0;
}