Skip to content

Commit

Permalink
Fix issue where id of entity created in template would be incorrectly…
Browse files Browse the repository at this point in the history
… cached
  • Loading branch information
SanderMertens committed Jan 3, 2025
1 parent 075d01a commit ded90f5
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 6 deletions.
11 changes: 9 additions & 2 deletions distr/flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -4684,6 +4684,11 @@ typedef struct ecs_script_id_t {
* stack pointers so we don't have to lookup variables by name. */
int32_t first_sp;
int32_t second_sp;

/* If true, the lookup result for this id cannot be cached. This is the case
* for entities that are defined inside of templates, which have different
* values for each instantiation. */
bool dynamic;
} ecs_script_id_t;

typedef struct ecs_script_tag_t {
Expand Down Expand Up @@ -40789,7 +40794,8 @@ void flecs_add_overrides_for_base(
ecs_id_t pair)
{
ecs_entity_t base = ecs_pair_second(world, pair);
ecs_assert(base != 0, ECS_INTERNAL_ERROR, NULL);
ecs_assert(base != 0, ECS_INVALID_PARAMETER,
"target of IsA pair is not alive");
ecs_table_t *base_table = ecs_get_table(world, base);
if (!base_table) {
return;
Expand Down Expand Up @@ -61695,7 +61701,7 @@ int flecs_script_eval_id(
{
ecs_entity_t second_from = 0;

if (id->eval) {
if (id->eval && !id->dynamic) {
/* Already resolved */
return 0;
}
Expand Down Expand Up @@ -61765,6 +61771,7 @@ int flecs_script_eval_id(
/* Targets may be defined by the template */
if (v->template) {
if (!flecs_script_find_template_entity(v, node, id->second)) {
id->dynamic = true;
return 0;
} else {
return -1;
Expand Down
5 changes: 5 additions & 0 deletions src/addons/script/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ typedef struct ecs_script_id_t {
* stack pointers so we don't have to lookup variables by name. */
int32_t first_sp;
int32_t second_sp;

/* If true, the lookup result for this id cannot be cached. This is the case
* for entities that are defined inside of templates, which have different
* values for each instantiation. */
bool dynamic;
} ecs_script_id_t;

typedef struct ecs_script_tag_t {
Expand Down
3 changes: 2 additions & 1 deletion src/addons/script/visit_eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ int flecs_script_eval_id(
{
ecs_entity_t second_from = 0;

if (id->eval) {
if (id->eval && !id->dynamic) {
/* Already resolved */
return 0;
}
Expand Down Expand Up @@ -369,6 +369,7 @@ int flecs_script_eval_id(
/* Targets may be defined by the template */
if (v->template) {
if (!flecs_script_find_template_entity(v, node, id->second)) {
id->dynamic = true;
return 0;
} else {
return -1;
Expand Down
3 changes: 2 additions & 1 deletion src/storage/table_graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,8 @@ void flecs_add_overrides_for_base(
ecs_id_t pair)
{
ecs_entity_t base = ecs_pair_second(world, pair);
ecs_assert(base != 0, ECS_INTERNAL_ERROR, NULL);
ecs_assert(base != 0, ECS_INVALID_PARAMETER,
"target of IsA pair is not alive");
ecs_table_t *base_table = ecs_get_table(world, base);
if (!base_table) {
return;
Expand Down
5 changes: 4 additions & 1 deletion test/script/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,10 @@
"component_w_assign_add",
"component_w_assign_mul",
"prop_after_const",
"const_from_prop"
"const_from_prop",
"redefine_nested_template_w_prefab",
"redefine_nested_template_w_prefab_2",
"redefine_nested_template_w_prefab_3"
]
}, {
"id": "Error",
Expand Down
137 changes: 137 additions & 0 deletions test/script/src/Template.c
Original file line number Diff line number Diff line change
Expand Up @@ -3281,3 +3281,140 @@ void Template_const_from_prop(void) {

ecs_fini(world);
}

void Template_redefine_nested_template_w_prefab(void) {
ecs_world_t *world = ecs_init();

ECS_COMPONENT(world, Position);

const char *expr =
HEAD "template Foo {"
LINE " foo_child {}"
LINE "}"
LINE ""
LINE "template Bar {"
LINE " prefab Base {"
LINE " Foo: {}"
LINE " }"
LINE ""
LINE " (IsA, Base)"
LINE "}"
LINE ""
LINE "e = Bar: { }"
LINE "e = Bar: { }";

test_assert(ecs_script_run(world, NULL, expr) == 0);

ecs_entity_t foo = ecs_lookup(world, "Foo");
test_assert(foo != 0);

ecs_entity_t bar = ecs_lookup(world, "Bar");
test_assert(bar != 0);

ecs_entity_t e = ecs_lookup(world, "e");
test_assert(e != 0);

ecs_entity_t base = ecs_lookup(world, "e.Base");
test_assert(base != 0);

ecs_entity_t foo_child = ecs_lookup(world, "e.foo_child");
test_assert(foo_child != 0);

test_assert(ecs_has_id(world, e, bar));
test_assert(ecs_has_pair(world, e, EcsIsA, base));
test_assert(ecs_has_id(world, e, foo));

ecs_fini(world);
}

void Template_redefine_nested_template_w_prefab_2(void) {
ecs_world_t *world = ecs_init();

ECS_COMPONENT(world, Position);

const char *expr =
HEAD "template Foo {"
LINE "}"
LINE ""
LINE "template Bar {"
LINE " prefab Base {"
LINE " Foo: {}"
LINE " }"
LINE ""
LINE " child : Base"
LINE "}"
LINE ""
LINE "e = Bar: { }"
LINE "e = Bar: { }";

test_assert(ecs_script_run(world, NULL, expr) == 0);

ecs_entity_t foo = ecs_lookup(world, "Foo");
test_assert(foo != 0);

ecs_entity_t bar = ecs_lookup(world, "Bar");
test_assert(bar != 0);

ecs_entity_t e = ecs_lookup(world, "e");
test_assert(e != 0);

ecs_entity_t base = ecs_lookup(world, "e.Base");
test_assert(base != 0);

ecs_entity_t child = ecs_lookup(world, "e.child");
test_assert(child != 0);

test_assert(ecs_has_id(world, e, bar));
test_assert(ecs_has_pair(world, child, EcsIsA, base));
test_assert(ecs_has_id(world, child, foo));

ecs_fini(world);
}

void Template_redefine_nested_template_w_prefab_3(void) {
ecs_world_t *world = ecs_init();

ECS_COMPONENT(world, Position);

const char *expr =
HEAD "template Foo {"
LINE " foo_child {}"
LINE "}"
LINE ""
LINE "template Bar {"
LINE " prefab Base {"
LINE " Foo: {}"
LINE " }"
LINE ""
LINE " child : Base"
LINE "}"
LINE ""
LINE "e = Bar: { }"
LINE "e = Bar: { }";

test_assert(ecs_script_run(world, NULL, expr) == 0);

ecs_entity_t foo = ecs_lookup(world, "Foo");
test_assert(foo != 0);

ecs_entity_t bar = ecs_lookup(world, "Bar");
test_assert(bar != 0);

ecs_entity_t e = ecs_lookup(world, "e");
test_assert(e != 0);

ecs_entity_t base = ecs_lookup(world, "e.Base");
test_assert(base != 0);

ecs_entity_t child = ecs_lookup(world, "e.child");
test_assert(child != 0);

ecs_entity_t foo_child = ecs_lookup(world, "e.child.foo_child");
test_assert(foo_child != 0);

test_assert(ecs_has_id(world, e, bar));
test_assert(ecs_has_pair(world, child, EcsIsA, base));
test_assert(ecs_has_id(world, child, foo));

ecs_fini(world);
}
17 changes: 16 additions & 1 deletion test/script/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,9 @@ void Template_component_w_assign_add(void);
void Template_component_w_assign_mul(void);
void Template_prop_after_const(void);
void Template_const_from_prop(void);
void Template_redefine_nested_template_w_prefab(void);
void Template_redefine_nested_template_w_prefab_2(void);
void Template_redefine_nested_template_w_prefab_3(void);

// Testsuite 'Error'
void Error_multi_line_comment_after_newline_before_newline_scope_open(void);
Expand Down Expand Up @@ -2479,6 +2482,18 @@ bake_test_case Template_testcases[] = {
{
"const_from_prop",
Template_const_from_prop
},
{
"redefine_nested_template_w_prefab",
Template_redefine_nested_template_w_prefab
},
{
"redefine_nested_template_w_prefab_2",
Template_redefine_nested_template_w_prefab_2
},
{
"redefine_nested_template_w_prefab_3",
Template_redefine_nested_template_w_prefab_3
}
};

Expand Down Expand Up @@ -4676,7 +4691,7 @@ static bake_test_suite suites[] = {
"Template",
NULL,
NULL,
71,
74,
Template_testcases
},
{
Expand Down

0 comments on commit ded90f5

Please sign in to comment.