From d2935ce633e81be4374e50e5affc81e53adff8b3 Mon Sep 17 00:00:00 2001 From: Sander Mertens Date: Tue, 5 Nov 2024 07:05:45 +0800 Subject: [PATCH] #1413 Fix issue where (OnInstantiate, Override) would not trigger OnSet --- distr/flecs.c | 81 +++++++++++++++++++++++++++++++------- src/addons/meta/meta.c | 35 +++++++++++------ src/observable.c | 43 +++++++++++++++++++- src/observer.c | 3 +- test/core/project.json | 3 ++ test/core/src/Trigger.c | 87 +++++++++++++++++++++++++++++++++++++++++ test/core/src/main.c | 17 +++++++- 7 files changed, 238 insertions(+), 31 deletions(-) diff --git a/distr/flecs.c b/distr/flecs.c index 2394d8d6e..bab1cf8f4 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -13802,6 +13802,7 @@ void flecs_emit( int32_t ider_i, ider_count = 0; bool is_pair = ECS_IS_PAIR(id); void *override_ptr = NULL; + bool override_base_added = false; ecs_table_record_t *base_tr = NULL; ecs_entity_t base = 0; bool id_can_override = can_override; @@ -13873,6 +13874,26 @@ void flecs_emit( override_ptr = base_table->data.columns[base_column].data; override_ptr = ECS_ELEM(override_ptr, ti->size, base_row); } + + /* For ids with override policy, check if base was added + * in same operation. This will determine later on + * whether we need to emit an OnSet event. */ + if (!(idr->flags & + (EcsIdOnInstantiateInherit|EcsIdOnInstantiateDontInherit))) { + int32_t base_i; + for (base_i = 0; base_i < id_count; base_i ++) { + ecs_id_t base_id = id_array[base_i]; + if (!ECS_IS_PAIR(base_id)) { + continue; + } + if (ECS_PAIR_FIRST(base_id) != EcsIsA) { + continue; + } + if (ECS_PAIR_SECOND(base_id) == (uint32_t)base) { + override_base_added = true; + } + } + } } } } @@ -13928,7 +13949,7 @@ void flecs_emit( ptr = ECS_ELEM(c->data, size, offset); } - /* safe, owned by observer */ + /* Safe, owned by observer */ ECS_CONST_CAST(int32_t*, it.sizes)[0] = size; if (override_ptr) { @@ -13937,6 +13958,26 @@ void flecs_emit( * with the value of the overridden component. */ flecs_override_copy(world, table, tr, ti, ptr, override_ptr, offset, count); + + /* If the base for this component got added in the same + * operation, generate an OnSet event as this is the + * first time this value is observed for the entity. */ + if (override_base_added) { + ecs_event_id_record_t *iders_set[5] = {0}; + int32_t ider_set_i, ider_set_count = + flecs_event_observers_get(er_onset, id, iders_set); + for (ider_set_i = 0; ider_set_i < ider_set_count; ider_set_i ++) { + ecs_event_id_record_t *ider = iders_set[ider_set_i]; + flecs_observers_invoke( + world, &ider->self, &it, table, 0); + ecs_assert(it.event_cur == evtx, + ECS_INTERNAL_ERROR, NULL); + flecs_observers_invoke( + world, &ider->self_up, &it, table, 0); + ecs_assert(it.event_cur == evtx, + ECS_INTERNAL_ERROR, NULL); + } + } } else if (er_onset && it.other_table) { /* If an override was removed, this re-exposes the * overridden component. Because this causes the actual @@ -14519,8 +14560,7 @@ void flecs_observers_invoke( while (ecs_map_next(&oit)) { ecs_observer_t *o = ecs_map_ptr(&oit); ecs_assert(it->table == table, ECS_INTERNAL_ERROR, NULL); - flecs_uni_observer_invoke( - world, o, it, table, trav); + flecs_uni_observer_invoke(world, o, it, table, trav); } ecs_table_unlock(it->world, table); @@ -50690,15 +50730,17 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsType), - .name = "type", .symbol = "EcsType" + .name = "type", .symbol = "EcsType", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsType), - .type.alignment = ECS_ALIGNOF(EcsType) + .type.alignment = ECS_ALIGNOF(EcsType), }); ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsPrimitive), - .name = "primitive", .symbol = "EcsPrimitive" + .name = "primitive", .symbol = "EcsPrimitive", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsPrimitive), .type.alignment = ECS_ALIGNOF(EcsPrimitive) @@ -50706,13 +50748,15 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = EcsConstant, - .name = "constant", .symbol = "EcsConstant" + .name = "constant", .symbol = "EcsConstant", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }) }); ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsEnum), - .name = "enum", .symbol = "EcsEnum" + .name = "enum", .symbol = "EcsEnum", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsEnum), .type.alignment = ECS_ALIGNOF(EcsEnum) @@ -50720,7 +50764,8 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsBitmask), - .name = "bitmask", .symbol = "EcsBitmask" + .name = "bitmask", .symbol = "EcsBitmask", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsBitmask), .type.alignment = ECS_ALIGNOF(EcsBitmask) @@ -50728,7 +50773,8 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsMember), - .name = "member", .symbol = "EcsMember" + .name = "member", .symbol = "EcsMember", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsMember), .type.alignment = ECS_ALIGNOF(EcsMember) @@ -50736,7 +50782,8 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsMemberRanges), - .name = "member_ranges", .symbol = "EcsMemberRanges" + .name = "member_ranges", .symbol = "EcsMemberRanges", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsMemberRanges), .type.alignment = ECS_ALIGNOF(EcsMemberRanges) @@ -50744,7 +50791,8 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsStruct), - .name = "struct", .symbol = "EcsStruct" + .name = "struct", .symbol = "EcsStruct", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsStruct), .type.alignment = ECS_ALIGNOF(EcsStruct) @@ -50752,7 +50800,8 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsArray), - .name = "array", .symbol = "EcsArray" + .name = "array", .symbol = "EcsArray", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsArray), .type.alignment = ECS_ALIGNOF(EcsArray) @@ -50760,7 +50809,8 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsVector), - .name = "vector", .symbol = "EcsVector" + .name = "vector", .symbol = "EcsVector", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsVector), .type.alignment = ECS_ALIGNOF(EcsVector) @@ -50768,7 +50818,8 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsOpaque), - .name = "opaque", .symbol = "EcsOpaque" + .name = "opaque", .symbol = "EcsOpaque", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsOpaque), .type.alignment = ECS_ALIGNOF(EcsOpaque) diff --git a/src/addons/meta/meta.c b/src/addons/meta/meta.c index 45660a439..eff54d968 100644 --- a/src/addons/meta/meta.c +++ b/src/addons/meta/meta.c @@ -1130,15 +1130,17 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsType), - .name = "type", .symbol = "EcsType" + .name = "type", .symbol = "EcsType", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsType), - .type.alignment = ECS_ALIGNOF(EcsType) + .type.alignment = ECS_ALIGNOF(EcsType), }); ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsPrimitive), - .name = "primitive", .symbol = "EcsPrimitive" + .name = "primitive", .symbol = "EcsPrimitive", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsPrimitive), .type.alignment = ECS_ALIGNOF(EcsPrimitive) @@ -1146,13 +1148,15 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = EcsConstant, - .name = "constant", .symbol = "EcsConstant" + .name = "constant", .symbol = "EcsConstant", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }) }); ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsEnum), - .name = "enum", .symbol = "EcsEnum" + .name = "enum", .symbol = "EcsEnum", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsEnum), .type.alignment = ECS_ALIGNOF(EcsEnum) @@ -1160,7 +1164,8 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsBitmask), - .name = "bitmask", .symbol = "EcsBitmask" + .name = "bitmask", .symbol = "EcsBitmask", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsBitmask), .type.alignment = ECS_ALIGNOF(EcsBitmask) @@ -1168,7 +1173,8 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsMember), - .name = "member", .symbol = "EcsMember" + .name = "member", .symbol = "EcsMember", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsMember), .type.alignment = ECS_ALIGNOF(EcsMember) @@ -1176,7 +1182,8 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsMemberRanges), - .name = "member_ranges", .symbol = "EcsMemberRanges" + .name = "member_ranges", .symbol = "EcsMemberRanges", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsMemberRanges), .type.alignment = ECS_ALIGNOF(EcsMemberRanges) @@ -1184,7 +1191,8 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsStruct), - .name = "struct", .symbol = "EcsStruct" + .name = "struct", .symbol = "EcsStruct", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsStruct), .type.alignment = ECS_ALIGNOF(EcsStruct) @@ -1192,7 +1200,8 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsArray), - .name = "array", .symbol = "EcsArray" + .name = "array", .symbol = "EcsArray", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsArray), .type.alignment = ECS_ALIGNOF(EcsArray) @@ -1200,7 +1209,8 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsVector), - .name = "vector", .symbol = "EcsVector" + .name = "vector", .symbol = "EcsVector", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsVector), .type.alignment = ECS_ALIGNOF(EcsVector) @@ -1208,7 +1218,8 @@ void FlecsMetaImport( ecs_component(world, { .entity = ecs_entity(world, { .id = ecs_id(EcsOpaque), - .name = "opaque", .symbol = "EcsOpaque" + .name = "opaque", .symbol = "EcsOpaque", + .add = ecs_ids(ecs_pair(EcsOnInstantiate, EcsDontInherit)) }), .type.size = sizeof(EcsOpaque), .type.alignment = ECS_ALIGNOF(EcsOpaque) diff --git a/src/observable.c b/src/observable.c index a9db3a439..d6bcdbe79 100644 --- a/src/observable.c +++ b/src/observable.c @@ -1236,6 +1236,7 @@ void flecs_emit( int32_t ider_i, ider_count = 0; bool is_pair = ECS_IS_PAIR(id); void *override_ptr = NULL; + bool override_base_added = false; ecs_table_record_t *base_tr = NULL; ecs_entity_t base = 0; bool id_can_override = can_override; @@ -1307,6 +1308,26 @@ void flecs_emit( override_ptr = base_table->data.columns[base_column].data; override_ptr = ECS_ELEM(override_ptr, ti->size, base_row); } + + /* For ids with override policy, check if base was added + * in same operation. This will determine later on + * whether we need to emit an OnSet event. */ + if (!(idr->flags & + (EcsIdOnInstantiateInherit|EcsIdOnInstantiateDontInherit))) { + int32_t base_i; + for (base_i = 0; base_i < id_count; base_i ++) { + ecs_id_t base_id = id_array[base_i]; + if (!ECS_IS_PAIR(base_id)) { + continue; + } + if (ECS_PAIR_FIRST(base_id) != EcsIsA) { + continue; + } + if (ECS_PAIR_SECOND(base_id) == (uint32_t)base) { + override_base_added = true; + } + } + } } } } @@ -1362,7 +1383,7 @@ void flecs_emit( ptr = ECS_ELEM(c->data, size, offset); } - /* safe, owned by observer */ + /* Safe, owned by observer */ ECS_CONST_CAST(int32_t*, it.sizes)[0] = size; if (override_ptr) { @@ -1371,6 +1392,26 @@ void flecs_emit( * with the value of the overridden component. */ flecs_override_copy(world, table, tr, ti, ptr, override_ptr, offset, count); + + /* If the base for this component got added in the same + * operation, generate an OnSet event as this is the + * first time this value is observed for the entity. */ + if (override_base_added) { + ecs_event_id_record_t *iders_set[5] = {0}; + int32_t ider_set_i, ider_set_count = + flecs_event_observers_get(er_onset, id, iders_set); + for (ider_set_i = 0; ider_set_i < ider_set_count; ider_set_i ++) { + ecs_event_id_record_t *ider = iders_set[ider_set_i]; + flecs_observers_invoke( + world, &ider->self, &it, table, 0); + ecs_assert(it.event_cur == evtx, + ECS_INTERNAL_ERROR, NULL); + flecs_observers_invoke( + world, &ider->self_up, &it, table, 0); + ecs_assert(it.event_cur == evtx, + ECS_INTERNAL_ERROR, NULL); + } + } } else if (er_onset && it.other_table) { /* If an override was removed, this re-exposes the * overridden component. Because this causes the actual diff --git a/src/observer.c b/src/observer.c index 9567a628e..15f9cb6db 100644 --- a/src/observer.c +++ b/src/observer.c @@ -437,8 +437,7 @@ void flecs_observers_invoke( while (ecs_map_next(&oit)) { ecs_observer_t *o = ecs_map_ptr(&oit); ecs_assert(it->table == table, ECS_INTERNAL_ERROR, NULL); - flecs_uni_observer_invoke( - world, o, it, table, trav); + flecs_uni_observer_invoke(world, o, it, table, trav); } ecs_table_unlock(it->world, table); diff --git a/test/core/project.json b/test/core/project.json index a1bdcf934..21de46d8c 100644 --- a/test/core/project.json +++ b/test/core/project.json @@ -1436,6 +1436,9 @@ "on_set_self_auto_override", "on_set_self_superset_auto_override", "on_set_superset_auto_override", + "on_set_self_on_instantiate_override", + "on_set_self_up_on_instantiate_override", + "on_set_up_on_instantiate_override", "not_only", "not_only_w_base", "not_only_w_base_no_match", diff --git a/test/core/src/Trigger.c b/test/core/src/Trigger.c index 129a4a2fb..b22443166 100644 --- a/test/core/src/Trigger.c +++ b/test/core/src/Trigger.c @@ -4654,6 +4654,93 @@ void Trigger_on_set_superset_auto_override(void) { ecs_fini(world); } +void Trigger_on_set_self_on_instantiate_override(void) { + ecs_world_t *world = ecs_mini(); + + ECS_COMPONENT(world, Position); + + ecs_entity_t base = ecs_insert(world, ecs_value(Position, {10, 20})); + + Probe ctx = {0}; + ecs_observer_init(world, &(ecs_observer_desc_t){ + .query.terms[0] = { + .id = ecs_id(Position), + .src.id = EcsSelf + }, + .events = {EcsOnSet}, + .callback = Trigger_w_value, + .ctx = &ctx + }); + + ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); + test_assert( ecs_has(world, inst, Position)); + test_assert( ecs_owns(world, inst, Position)); + + test_int(ctx.invoked, 1); + test_int(ctx.count, 1); + test_int(ctx.e[0], inst); + test_int(ctx.s[0][0], 0); + + ecs_fini(world); +} + +void Trigger_on_set_self_up_on_instantiate_override(void) { + ecs_world_t *world = ecs_mini(); + + ECS_COMPONENT(world, Position); + + ecs_entity_t base = ecs_insert(world, ecs_value(Position, {10, 20})); + + Probe ctx = {0}; + ecs_observer_init(world, &(ecs_observer_desc_t){ + .query.terms[0] = { + .id = ecs_id(Position), + .src.id = EcsSelf|EcsUp + }, + .events = {EcsOnSet}, + .callback = Trigger_w_value, + .ctx = &ctx + }); + + ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); + test_assert( ecs_has(world, inst, Position)); + test_assert( ecs_owns(world, inst, Position)); + + test_int(ctx.invoked, 1); + test_int(ctx.count, 1); + test_int(ctx.e[0], inst); + test_int(ctx.s[0][0], 0); + + ecs_fini(world); +} + +void Trigger_on_set_up_on_instantiate_override(void) { + ecs_world_t *world = ecs_mini(); + + ECS_COMPONENT(world, Position); + + ecs_entity_t base = ecs_insert(world, ecs_value(Position, {10, 20})); + + Probe ctx = {0}; + ecs_observer_init(world, &(ecs_observer_desc_t){ + .query.terms[0] = { + .id = ecs_id(Position), + .src.id = EcsUp + }, + .events = {EcsOnSet}, + .callback = Trigger_w_value, + .ctx = &ctx + }); + + ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base); + test_assert( ecs_has(world, inst, Position)); + test_assert( ecs_owns(world, inst, Position)); + + test_int(ctx.invoked, 0); + + ecs_fini(world); +} + void Trigger_not_only(void) { ecs_world_t *world = ecs_mini(); diff --git a/test/core/src/main.c b/test/core/src/main.c index d5fc619d5..ecb758b3b 100644 --- a/test/core/src/main.c +++ b/test/core/src/main.c @@ -1377,6 +1377,9 @@ void Trigger_on_set_self_superset_from_child_base_of_prefab(void); void Trigger_on_set_self_auto_override(void); void Trigger_on_set_self_superset_auto_override(void); void Trigger_on_set_superset_auto_override(void); +void Trigger_on_set_self_on_instantiate_override(void); +void Trigger_on_set_self_up_on_instantiate_override(void); +void Trigger_on_set_up_on_instantiate_override(void); void Trigger_not_only(void); void Trigger_not_only_w_base(void); void Trigger_not_only_w_base_no_match(void); @@ -7595,6 +7598,18 @@ bake_test_case Trigger_testcases[] = { "on_set_superset_auto_override", Trigger_on_set_superset_auto_override }, + { + "on_set_self_on_instantiate_override", + Trigger_on_set_self_on_instantiate_override + }, + { + "on_set_self_up_on_instantiate_override", + Trigger_on_set_self_up_on_instantiate_override + }, + { + "on_set_up_on_instantiate_override", + Trigger_on_set_up_on_instantiate_override + }, { "not_only", Trigger_not_only @@ -11298,7 +11313,7 @@ static bake_test_suite suites[] = { "Trigger", NULL, NULL, - 117, + 120, Trigger_testcases }, {