#include #include // Component hooks are callbacks that can be registered for a type that are // invoked during different parts of the component lifecycle. typedef struct { char *value; // Pointer to external memory } String; // Resource management hooks. The convenience macros hide details of // the callback signature, while allowing hooks to be called on multiple // entities. // The constructor should initialize the component value. ECS_CTOR(String, ptr, { ecs_trace("Ctor"); ptr->value = NULL; }) // The destructor should free resources. ECS_DTOR(String, ptr, { ecs_trace("Dtor"); ecs_os_free(ptr->value); }) // The move hook should move resources from one location to another. ECS_MOVE(String, dst, src, { ecs_trace("Move"); ecs_os_free(dst->value); dst->value = src->value; src->value = NULL; // This makes sure the value doesn't get deleted twice, // as the destructor is still invoked after a move. }) // The copy hook should copy resources from one location to another. ECS_COPY(String, dst, src, { ecs_trace("Copy"); ecs_os_free(dst->value); dst->value = ecs_os_strdup(src->value); }) // This callback is used for the add, remove and set hooks. Note that the // signature is the same as systems, triggers, observers. void hook_callback(ecs_iter_t *it) { ecs_world_t *world = it->world; ecs_entity_t event = it->event; for (int i = 0; i < it->count; i ++) { ecs_entity_t e = it->entities[i]; ecs_trace("%s: %s", ecs_get_name(world, event), ecs_get_name(world, e)); } } int main(int argc, char *argv[]) { ecs_world_t *world = ecs_init_w_args(argc, argv); ECS_COMPONENT(world, String); ECS_TAG(world, Tag); ecs_set_hooks(world, String, { /* Resource management hooks. These hooks should primarily be used for * managing memory used by the component. */ .ctor = ecs_ctor(String), .move = ecs_move(String), .copy = ecs_copy(String), .dtor = ecs_dtor(String), /* Lifecycle hooks. These hooks should be used for application logic. */ .on_add = hook_callback, .on_remove = hook_callback, .on_set = hook_callback }); ecs_log_set_level(0); ecs_entity_t e = ecs_new_entity(world, "Entity"); ecs_trace("ecs_add(world, e, String)"); ecs_log_push(); ecs_add(world, e, String); ecs_log_pop(); ecs_trace("ecs_set(world, e, String, {\"Hello World\"})"); ecs_log_push(); ecs_set(world, e, String, {ECS_CONST_CAST(char*, "Hello World")}); ecs_log_pop(); // This operation changes the entity's archetype, which invokes a move ecs_trace("ecs_add(world, e, Tag)"); ecs_log_push(); ecs_add(world, e, Tag); ecs_log_pop(); ecs_trace("ecs_delete(world, e)"); ecs_log_push(); ecs_delete(world, e); ecs_log_pop(); ecs_log_set_level(-1); return ecs_fini(world); // Output: // info: ecs_add(world, e, String) // info: | Ctor // info: | OnAdd: Entity // info: ecs_set(world, e, String, {"Hello World"}) // info: | Copy // info: | OnSet: Entity // info: ecs_add(world, e, Tag) // info: | Ctor // info: | Move // info: | Dtor // info: ecs_delete(world, e) // info: | OnRemove: Entity // info: | Dtor }