#include #include typedef struct Data { int x; } Data; typedef struct Test { Data* ptr; } Test; ECS_COMPONENT_DECLARE(Test); ECS_CTOR(Test, ptr, { ptr->ptr = ecs_os_malloc(sizeof(Data)); ptr->ptr->x = 0; // Default value printf("ctor: %d\n", ptr->ptr->x); }) ECS_DTOR(Test, ptr, { printf("dtor: %d\n", ptr->ptr->x); ecs_os_free(ptr->ptr); }) ECS_MOVE(Test, dst, src, { printf("move: %d->%d\n", src->ptr->x, dst->ptr->x); dst->ptr = src->ptr; // Clear the pointer in src since it's been moved tp dst and we // don't want to free it when `src` ges destroyed src->ptr = NULL; }) void testRemoved(ecs_iter_t *it) { Test *test = ecs_field(it, Test, 1); for (int i = 0; i < it->count; i++) { printf("on_remove: %d\n", test[i].ptr->x); } } void testSet(ecs_iter_t *it) { Test *test = ecs_field(it, Test, 1); for (int i = 0; i < it->count; i++) { printf("on_set: %d\n", test[i].ptr->x); } } void ecs_copy_illegal(void *dst, const void *src, int32_t c, const ecs_type_info_t *ti) { ecs_abort(ECS_INVALID_OPERATION, "invalid copy assignment for %s", ti->name); } int main(int argc, char *argv[]) { ecs_world_t *ecs = ecs_init(); ECS_COMPONENT_DEFINE(ecs, Test); ecs_set_hooks(ecs, Test, { .ctor = ecs_ctor(Test), .dtor = ecs_dtor(Test), .move = ecs_move(Test), .copy = ecs_copy_illegal, // Prevent Test from being copied so that they never share the same pointer .on_remove = testRemoved, .on_set = testSet }); ecs_entity_t entity = ecs_new_id(ecs); Test* test = ecs_emplace(ecs, entity, Test); // Emplace the component, this doesn't call the ctor allowing us to initialize the data in the table directly Data* ptr = ecs_os_malloc(sizeof(Data)); ptr->x = 1; test->ptr = ptr; ecs_modified(ecs, entity, Test); // Tell the ECS that we are done with modifying the component // Modify the data in the component without doing any copy/move test = ecs_get_mut(ecs, entity, Test); test->ptr->x = 2; ecs_modified(ecs, entity, Test); ecs_remove(ecs, entity, Test); // testRemoved called for {2} // Since the component was previously removed this will call the constructor to initialize the // default value in the table, and then return that. test = ecs_get_mut(ecs, entity, Test); test->ptr->x = 3; ecs_modified(ecs, entity, Test); ecs_defer_begin(ecs); ecs_remove(ecs, entity, Test); test = ecs_get_mut(ecs, entity, Test); test->ptr->x = 4; ecs_modified(ecs, entity, Test); ecs_defer_end(ecs); ecs_fini(ecs); // testRemoved called for {4} }