Files
PixelDefense/engine/libs/flecs/test/api/src/TriggerOnSet.c

680 lines
15 KiB
C

#include <api.h>
static
void Trigger(ecs_iter_t *it) {
probe_iter(it);
}
static
void OnSet(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1);
Velocity *v = NULL;
if (it->field_count >= 2) {
v = ecs_field(it, Velocity, 2);
}
probe_iter(it);
int i;
for (i = 0; i < it->count; i ++) {
p[i].x ++;
if (v) {
v[i].x = p[i].x;
v[i].y = p[i].y;
}
}
}
static bool dummy_called = false;
static
void Dummy(ecs_iter_t *it) {
dummy_called = true;
}
void TriggerOnSet_set(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_OBSERVER(world, OnSet, EcsOnSet, Position);
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t e = ecs_new(world, Position);
test_int(ctx.count, 0);
ecs_set(world, e, Position, {10, 20});
test_int(ctx.count, 1);
test_int(ctx.invoked, 1);
test_int(ctx.system, OnSet);
test_int(ctx.term_count, 1);
test_null(ctx.param);
test_int(ctx.e[0], e);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
const Position *p = ecs_get(world, e, Position);
test_assert(p != NULL);
test_int(p->x, 11);
test_int(p->y, 20);
ecs_fini(world);
}
void TriggerOnSet_set_new(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_OBSERVER(world, OnSet, EcsOnSet, Position);
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
test_int(ctx.count, 1);
test_int(ctx.invoked, 1);
test_int(ctx.system, OnSet);
test_int(ctx.term_count, 1);
test_null(ctx.param);
test_int(ctx.e[0], e);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
const Position *p = ecs_get(world, e, Position);
test_assert(p != NULL);
test_int(p->x, 11);
test_int(p->y, 20);
ecs_fini(world);
}
void TriggerOnSet_set_again(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_OBSERVER(world, OnSet, EcsOnSet, Position);
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t e = ecs_new(world, Position);
test_int(ctx.count, 0);
ecs_set(world, e, Position, {10, 20});
test_int(ctx.count, 1);
test_int(ctx.invoked, 1);
test_int(ctx.system, OnSet);
test_int(ctx.term_count, 1);
test_null(ctx.param);
test_int(ctx.e[0], e);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
const Position *p = ecs_get(world, e, Position);
test_assert(p != NULL);
test_int(p->x, 11);
test_int(p->y, 20);
ecs_set_ptr(world, e, Position, p);
p = ecs_get(world, e, Position);
test_assert(p != NULL);
test_int(p->x, 12);
test_int(p->y, 20);
ecs_fini(world);
}
void TriggerOnSet_clone(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_OBSERVER(world, OnSet, EcsOnSet, Position);
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
test_int(ctx.count, 1);
test_int(ctx.invoked, 1);
test_int(ctx.system, OnSet);
test_int(ctx.term_count, 1);
test_null(ctx.param);
test_int(ctx.e[0], e1);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
const Position *p = ecs_get(world, e1, Position);
test_assert(p != NULL);
test_int(p->x, 11);
test_int(p->y, 20);
ecs_os_zeromem(&ctx);
ecs_clone(world, 0, e1, false);
/* OnSet function should not have been called, because value has not been
* copied */
test_int(ctx.count, 0);
ecs_fini(world);
}
void TriggerOnSet_clone_w_value(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_OBSERVER(world, OnSet, EcsOnSet, Position);
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
test_int(ctx.count, 1);
test_int(ctx.invoked, 1);
test_int(ctx.system, OnSet);
test_int(ctx.term_count, 1);
test_null(ctx.param);
test_int(ctx.e[0], e1);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
const Position *p = ecs_get(world, e1, Position);
test_assert(p != NULL);
test_int(p->x, 11);
test_int(p->y, 20);
ecs_os_zeromem(&ctx);
ecs_entity_t e2 = ecs_clone(world, 0, e1, true);
test_int(ctx.count, 1);
test_int(ctx.invoked, 1);
test_int(ctx.system, OnSet);
test_int(ctx.term_count, 1);
test_null(ctx.param);
test_int(ctx.e[0], e2);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
p = ecs_get(world, e2, Position);
test_assert(p != NULL);
test_int(p->x, 12);
test_int(p->y, 20);
ecs_fini(world);
}
static bool add_called;
static bool set_called;
static
void OnAdd_check_order(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1);
test_assert(!add_called);
test_assert(!set_called);
probe_iter(it);
int i;
for (i = 0; i < it->count; i ++) {
p[i].x = 1;
p[i].y = 2;
}
add_called = true;
}
static
void OnSet_check_order(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1);
probe_iter(it);
test_assert(add_called);
test_assert(!set_called);
int i;
for (i = 0; i < it->count; i ++) {
p[i].x ++;
}
set_called = true;
}
void TriggerOnSet_set_and_add_system(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_OBSERVER(world, OnSet_check_order, EcsOnSet, Position);
ECS_OBSERVER(world, OnAdd_check_order, EcsOnAdd, Position);
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t e = ecs_new(world, 0);
test_int(ctx.count, 0);
ecs_set(world, e, Position, {10, 20});
test_int(ctx.count, 2);
test_int(ctx.invoked, 2);
test_int(ctx.system, OnSet_check_order);
test_int(ctx.term_count, 1);
test_null(ctx.param);
test_int(ctx.e[0], e);
test_int(ctx.e[1], e);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
test_int(ctx.c[1][0], ecs_id(Position));
test_int(ctx.s[1][0], 0);
const Position *p = ecs_get(world, e, Position);
test_assert(p != NULL);
test_int(p->x, 11);
test_int(p->y, 20);
test_assert(set_called);
ecs_fini(world);
}
static
void OnSetShared(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1);
Velocity *v = NULL;
if (it->field_count >= 2) {
v = ecs_field(it, Velocity, 2);
}
probe_iter(it);
int i;
for (i = 0; i < it->count; i ++) {
if (v) {
v[i].x = p->x;
v[i].y = p->y;
}
}
}
void TriggerOnSet_on_set_after_override(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_PREFAB(world, Prefab, Position);
ecs_set(world, Prefab, Position, {1, 3});
ECS_OBSERVER(world, OnSetShared, EcsOnSet, Position);
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
/* instantiate prefab */
ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Prefab);
test_int(ctx.count, 1);
test_int(ctx.invoked, 1);
test_int(ctx.system, OnSetShared);
test_int(ctx.term_count, 1);
test_null(ctx.param);
test_int(ctx.e[0], e);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], Prefab);
const Position *p = ecs_get(world, e, Position);
test_assert(p != NULL);
test_assert(p == ecs_get(world, Prefab, Position));
test_int(p->x, 1);
test_int(p->y, 3);
/* Override component. Should not call OnSet system because the value of the
* component has not changed. */
ecs_os_zeromem(&ctx);
ecs_add(world, e, Position);
test_int(ctx.count, 0);
test_int(ctx.invoked, 0);
const Position *p_after = ecs_get(world, e, Position);
test_assert(p_after != NULL);
test_assert(p != p_after);
test_int(p_after->x, 1);
test_int(p_after->y, 3);
/* Set component */
ecs_set(world, e, Position, {2, 4});
test_int(ctx.count, 1);
test_int(ctx.invoked, 1);
test_int(ctx.system, OnSetShared);
test_int(ctx.term_count, 1);
test_null(ctx.param);
test_int(ctx.e[0], e);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
p_after = ecs_get(world, e, Position);
test_assert(p_after != NULL);
test_assert(p != p_after);
test_int(p_after->x, 2);
test_int(p_after->y, 4);
ecs_fini(world);
}
void TriggerOnSet_on_set_after_override_w_new(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_PREFAB(world, Prefab, Position, OVERRIDE | Position);
ecs_set(world, Prefab, Position, {1, 3});
Probe ctx = {0};
ecs_entity_t t1 = ecs_observer_init(world, &(ecs_observer_desc_t){
.filter.terms[0].id = ecs_id(Position),
.events = {EcsOnSet},
.callback = OnSet,
.ctx = &ctx
});
ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Prefab);
test_int(ctx.count, 1);
test_int(ctx.invoked, 1);
test_int(ctx.system, t1);
test_int(ctx.term_count, 1);
test_null(ctx.param);
test_int(ctx.e[0], e);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
const Position *p = ecs_get(world, e, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 3);
ecs_fini(world);
}
void TriggerOnSet_on_set_after_override_w_new_w_count(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_PREFAB(world, Prefab, Position, OVERRIDE | Position);
ecs_set(world, Prefab, Position, {1, 3});
ECS_OBSERVER(world, OnSet, EcsOnSet, Position);
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
const ecs_entity_t *ids = ecs_bulk_new_w_id(world, ecs_pair(EcsIsA, Prefab), 3);
test_assert(ids != NULL);
test_int(ctx.count, 3);
test_int(ctx.invoked, 1);
test_int(ctx.system, OnSet);
test_int(ctx.term_count, 1);
test_null(ctx.param);
test_int(ctx.e[0], ids[0]);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
int i;
for (i = 0; i < 3; i ++) {
const Position *p = ecs_get(world, ids[i], Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 3);
}
ecs_fini(world);
}
void TriggerOnSet_on_set_after_override_1_of_2_overridden(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_PREFAB(world, Prefab, Position, OVERRIDE | Position);
ecs_set(world, Prefab, Position, {1, 3});
ECS_OBSERVER(world, OnSet, EcsOnSet, Position);
Probe ctx = {0};
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Prefab);
test_int(ctx.count, 1);
test_int(ctx.invoked, 1);
test_int(ctx.system, OnSet);
test_int(ctx.term_count, 1);
test_null(ctx.param);
test_int(ctx.e[0], e);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], 0);
const Position *p = ecs_get(world, e, Position);
test_assert(p != NULL);
test_int(p->x, 2);
test_int(p->y, 3);
ecs_fini(world);
}
static
void SetPosition(ecs_iter_t *it) {
probe_iter(it);
}
void TriggerOnSet_on_set_after_snapshot_restore(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_OBSERVER(world, SetPosition, EcsOnSet, Position);
const ecs_entity_t *ids = ecs_bulk_new(world, Position, 10);
test_assert(ids != NULL);
ecs_entity_t id_arr[10];
memcpy(id_arr, ids, sizeof(ecs_entity_t) * 10);
int32_t i;
for (i = 0; i < 10; i ++) {
test_assert(ecs_has(world, ids[i], Position));
ecs_set(world, ids[i], Position, {i, i * 2});
}
Probe ctx = { 0 };
ecs_set_ctx(world, &ctx, NULL);
ecs_snapshot_t *s = ecs_snapshot_take(world);
test_int(ctx.invoked, 0);
/* Delete one entity, so we have more confidence we're triggering on the
* right entities */
ecs_delete(world, id_arr[0]);
test_int(ctx.invoked, 0);
ecs_snapshot_restore(world, s);
test_int(ctx.count, 10);
test_int(ctx.invoked, 1);
test_int(ctx.system, SetPosition);
test_int(ctx.term_count, 1);
test_int(ctx.c[0][0], ecs_id(Position));
test_null(ctx.param);
for (i = 0; i < 10; i ++) {
test_int(ctx.e[i], id_arr[i]);
}
ecs_fini(world);
}
void TriggerOnSet_emplace(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_observer_init(world, &(ecs_observer_desc_t){
.filter.terms[0].id = ecs_id(Position),
.events = {EcsOnSet},
.callback = Dummy
});
ecs_entity_t e = ecs_new_id(world);
test_assert(e != 0);
test_int(dummy_called, 0);
Position *p = ecs_emplace(world, e, Position);
test_assert(p != NULL);
test_int(dummy_called, 0);
ecs_modified(world, e, Position);
test_bool(dummy_called, true);
ecs_fini(world);
}
void TriggerOnSet_un_set_tag_w_remove(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_observer_init(world, &(ecs_observer_desc_t){
.filter.terms[0].id = Tag,
.events = {EcsUnSet},
.callback = Dummy
});
ecs_entity_t e = ecs_new_id(world);
test_assert(e != 0);
test_int(dummy_called, 0);
ecs_add(world, e, Tag);
test_int(dummy_called, 0);
ecs_remove(world, e, Tag);
test_int(dummy_called, 1);
ecs_fini(world);
}
void TriggerOnSet_un_set_tag_w_clear(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_observer_init(world, &(ecs_observer_desc_t){
.filter.terms[0].id = Tag,
.events = {EcsUnSet},
.callback = Dummy
});
ecs_entity_t e = ecs_new_id(world);
test_assert(e != 0);
test_int(dummy_called, 0);
ecs_add(world, e, Tag);
test_int(dummy_called, 0);
ecs_clear(world, e);
test_int(dummy_called, 1);
ecs_fini(world);
}
void TriggerOnSet_un_set_tag_w_delete(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_observer_init(world, &(ecs_observer_desc_t){
.filter.terms[0].id = Tag,
.events = {EcsUnSet},
.callback = Dummy
});
ecs_entity_t e = ecs_new_id(world);
test_assert(e != 0);
test_int(dummy_called, 0);
ecs_add(world, e, Tag);
test_int(dummy_called, 0);
ecs_delete(world, e);
test_int(dummy_called, 1);
ecs_fini(world);
}
void TriggerOnSet_on_set_after_remove_override(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_ENTITY(world, Base, Position);
ECS_OBSERVER(world, Trigger, EcsOnSet, Position);
Probe ctx = { 0 };
ecs_set_ctx(world, &ctx, NULL);
ecs_entity_t e = ecs_new(world, Position);
test_int(ctx.invoked, 0);
ecs_add_pair(world, e, EcsIsA, Base);
test_int(ctx.invoked, 0);
ecs_remove(world, e, Position);
test_int(ctx.invoked, 1);
test_int(ctx.count, 1);
test_int(ctx.system, Trigger);
test_int(ctx.term_count, 1);
test_null(ctx.param);
test_int(ctx.e[0], e);
test_int(ctx.c[0][0], ecs_id(Position));
test_int(ctx.s[0][0], Base);
ecs_fini(world);
}