API Reference
Include the public API with:
#include <siecs.h>#include <siecs.h>
#include <siecs.h>Core Types
Section titled “Core Types”| Type | Meaning |
|---|---|
ecs_entity_t | Entity handle. |
ecs_component_t | Component id. |
ecs_query_id_t | Query id. |
ecs_system_id_t | System id. Id 0 is reserved. |
ecs_event_t | Observer event id. |
ecs_module_id_t | Module id. Id 0 is reserved. |
ecs_observer_id_t | Observer id. |
ecs_iter_t | Query iterator. Users may read count. |
void ecs_init(void);
void ecs_init_w_features(const ecs_world_feat_desc_t *features);
void ecs_fini(void);#include <siecs.h>
void ecs_init(void);
void ecs_init_w_features(const ecs_world_feat_desc_t *features);
void ecs_fini(void);typedef struct {
bool rest;
uint16_t target_fps;
} ecs_world_feat_desc_t;
#define ecs_with_features(...)#include <siecs.h>
typedef struct {
bool rest;
uint16_t target_fps;
} ecs_world_feat_desc_t;
#define ecs_with_features(...)rest starts the REST explorer server when the addon is built in. target_fps
caps ecs_progress() by sleeping for the remaining frame time when non-zero.
Components
Section titled “Components”ECS_COMPONENT_DECLARE(Name, { /* fields */ });
ECS_COMPONENT_DEFINE(Name);
ECS_COMPONENT_REGISTER(Name);#include <siecs.h>
ECS_COMPONENT_DECLARE(Name, { /* fields */ });
ECS_COMPONENT_DEFINE(Name);
ECS_COMPONENT_REGISTER(Name);Built-in components declared by the public API:
ECS_RELATION_DECLARE(ChildOf);
ECS_COMPONENT_DECLARE(Name, { char *value; });
ECS_COMPONENT_DECLARE(Disabled, {});
ECS_COMPONENT_DECLARE(Abstract, {});#include <siecs.h>
ECS_RELATION_DECLARE(ChildOf);
ECS_COMPONENT_DECLARE(Name, { char *value; });
ECS_COMPONENT_DECLARE(Disabled, {});
ECS_COMPONENT_DECLARE(Abstract, {});Disabled excludes an entity from queries by default. A query can match
disabled entities by mentioning Disabled explicitly, for example with
ecs_filter(Disabled).
Abstract marks an entity as a prefab-like base that should not receive direct
component add, set, or remove operations from normal application code.
#define ecs_component(...)
ecs_component_t ecs_component_init(const ecs_component_desc_t *desc);#include <siecs.h>
#define ecs_component(...)
ecs_component_t ecs_component_init(const ecs_component_desc_t *desc);typedef struct {
const char *name;
uint64_t size;
ecs_component_on_set_t on_set;
ecs_component_on_remove_t on_remove;
ecs_component_on_add_t on_add;
uint32_t relation_flags;
const sireflect_struct_desc_t *struct_desc;
} ecs_component_desc_t;#include <siecs.h>
typedef struct {
const char *name;
uint64_t size;
ecs_component_on_set_t on_set;
ecs_component_on_remove_t on_remove;
ecs_component_on_add_t on_add;
uint32_t relation_flags;
const sireflect_struct_desc_t *struct_desc;
} ecs_component_desc_t;Entities
Section titled “Entities”ecs_entity_t ecs_new(void);
bool ecs_is_alive(const ecs_entity_t entity);
void ecs_kill(ecs_entity_t entity);
void ecs_is_a(ecs_entity_t entity, ecs_entity_t target);
bool ecs_is(ecs_entity_t entity, ecs_entity_t target);#include <siecs.h>
ecs_entity_t ecs_new(void);
bool ecs_is_alive(const ecs_entity_t entity);
void ecs_kill(ecs_entity_t entity);
void ecs_is_a(ecs_entity_t entity, ecs_entity_t target);
bool ecs_is(ecs_entity_t entity, ecs_entity_t target);ecs_is_a() creates an inheritance link from entity to target.
ecs_is() checks whether an entity is or inherits from target.
Component Access
Section titled “Component Access”Typed helpers:
ecs_add(entity, Component);
ecs_remove(entity, Component);
ecs_has(entity, Component);
ecs_get(entity, Component);
ecs_try_get(entity, Component);
ecs_set(entity, Component, { /* value */ });#include <siecs.h>
ecs_add(entity, Component);
ecs_remove(entity, Component);
ecs_has(entity, Component);
ecs_get(entity, Component);
ecs_try_get(entity, Component);
ecs_set(entity, Component, { /* value */ });Id-based functions:
void ecs_add_cid(ecs_entity_t entity, ecs_component_t id);
void ecs_remove_cid(ecs_entity_t entity, ecs_component_t id);
bool ecs_has_cid(const ecs_entity_t entity, ecs_component_t id);
void *ecs_get_cid(ecs_entity_t entity, ecs_component_t id);
void *ecs_try_get_cid(ecs_entity_t entity, ecs_component_t cid);
void ecs_set_cid(ecs_entity_t entity, ecs_component_t id, const void *data);#include <siecs.h>
void ecs_add_cid(ecs_entity_t entity, ecs_component_t id);
void ecs_remove_cid(ecs_entity_t entity, ecs_component_t id);
bool ecs_has_cid(const ecs_entity_t entity, ecs_component_t id);
void *ecs_get_cid(ecs_entity_t entity, ecs_component_t id);
void *ecs_try_get_cid(ecs_entity_t entity, ecs_component_t cid);
void ecs_set_cid(ecs_entity_t entity, ecs_component_t id, const void *data);ecs_get() and ecs_get_cid() assume the component exists. Use
ecs_try_get() or ecs_try_get_cid() when absence is valid.
void ecs_with(ecs_component_t component, ecs_component_t require);#include <siecs.h>
void ecs_with(ecs_component_t component, ecs_component_t require);ecs_with(component, require) declares that adding component also adds
require first.
Requirement cycles are invalid and are asserted in debug builds when declared.
Resources
Section titled “Resources”Resources are typed values stored once per world. They use ecs_resource_t
ids, separate from component ids.
ECS_RESOURCE_DECLARE(Time, { float dt; });
ECS_RESOURCE_DEFINE(Time);
ECS_RESOURCE_REGISTER(Time);
ECS_RESOURCE(Time, { float dt; });#include <siecs.h>
ECS_RESOURCE_DECLARE(Time, { float dt; });
ECS_RESOURCE_DEFINE(Time);
ECS_RESOURCE_REGISTER(Time);
ECS_RESOURCE(Time, { float dt; });Typed helpers:
ecs_set_resource(Time, { .dt = 0.016f });
ecs_get_resource(Time);
ecs_get_resource_read(Time);
ecs_try_get_resource(Time);
ecs_try_get_resource_read(Time);
ecs_has_resource(Time);
ecs_remove_resource(Time);#include <siecs.h>
ecs_set_resource(Time, { .dt = 0.016f });
ecs_get_resource(Time);
ecs_get_resource_read(Time);
ecs_try_get_resource(Time);
ecs_try_get_resource_read(Time);
ecs_has_resource(Time);
ecs_remove_resource(Time);Id-based functions:
ecs_resource_t ecs_resource_register(ecs_resource_t *id, const ecs_resource_desc_t *desc);
ecs_resource_t ecs_resource_init(const ecs_resource_desc_t *desc);
void ecs_set_resource_rid(ecs_resource_t id, const void *data);
void *ecs_resource_rid(ecs_resource_t id);
void *ecs_try_resource_rid(ecs_resource_t id);
bool ecs_has_resource_rid(const ecs_resource_t id);
void ecs_remove_resource_rid(ecs_resource_t id);#include <siecs.h>
ecs_resource_t ecs_resource_register(ecs_resource_t *id, const ecs_resource_desc_t *desc);
ecs_resource_t ecs_resource_init(const ecs_resource_desc_t *desc);
void ecs_set_resource_rid(ecs_resource_t id, const void *data);
void *ecs_resource_rid(ecs_resource_t id);
void *ecs_try_resource_rid(ecs_resource_t id);
bool ecs_has_resource_rid(const ecs_resource_t id);
void ecs_remove_resource_rid(ecs_resource_t id);ecs_resource_rid() asserts if the resource is absent. Use
ecs_try_resource_rid() when absence is valid. Resource on_set hooks run when
a resource is set, and on_remove hooks run when a resource is removed or when
the world is destroyed.
Queries
Section titled “Queries”#define ecs_query(...)
uint32_t ecs_query_init(const ecs_query_desc_t *query);
void ecs_query_fini(ecs_query_id_t qid);#include <siecs.h>
#define ecs_query(...)
uint32_t ecs_query_init(const ecs_query_desc_t *query);
void ecs_query_fini(ecs_query_id_t qid);typedef enum {
EcsIn,
EcsOut,
EcsInOut,
EcsInOptional,
EcsInOutOptional,
EcsFilter,
EcsNot,
} ecs_term_access_t;
typedef struct {
ecs_component_t id;
ecs_term_access_t access;
} ecs_query_term_t;
typedef struct {
ecs_query_term_t terms[16];
ecs_entity_t is_a;
} ecs_query_desc_t;#include <siecs.h>
typedef enum {
EcsIn,
EcsOut,
EcsInOut,
EcsInOptional,
EcsInOutOptional,
EcsFilter,
EcsNot,
} ecs_term_access_t;
typedef struct {
ecs_component_t id;
ecs_term_access_t access;
} ecs_query_term_t;
typedef struct {
ecs_query_term_t terms[16];
ecs_entity_t is_a;
} ecs_query_desc_t;is_a restricts the query to entities that inherit from the given target. The
match is transitive through the inheritance chain.
ecs_in(Component);
ecs_out(Component);
ecs_inout(Component);
ecs_in_optional(Component);
ecs_inout_optional(Component);
ecs_filter(Component);
ecs_not(Component);#include <siecs.h>
ecs_in(Component);
ecs_out(Component);
ecs_inout(Component);
ecs_in_optional(Component);
ecs_inout_optional(Component);
ecs_filter(Component);
ecs_not(Component);ecs_field() returns EcsIn, EcsOut, EcsInOut, EcsInOptional, and
EcsInOutOptional terms in declaration order. Optional fields return NULL
for batches whose table does not contain the component.
Queries implicitly add ecs_not(Disabled) unless their descriptor already
contains a term for Disabled. The implicit term is used by plain queries,
systems, and observers.
ecs_iter_t ecs_query_iter(ecs_query_id_t query_id);
bool ecs_iter_next(ecs_iter_t *it);
void *ecs_field(ecs_iter_t *it, uint16_t field_index);#include <siecs.h>
ecs_iter_t ecs_query_iter(ecs_query_id_t query_id);
bool ecs_iter_next(ecs_iter_t *it);
void *ecs_field(ecs_iter_t *it, uint16_t field_index);Observers
Section titled “Observers”#define EcsOnAdd 0
#define EcsOnRemove 1
#define EcsOnSet 2#include <siecs.h>
#define EcsOnAdd 0
#define EcsOnRemove 1
#define EcsOnSet 2#define ecs_observer(...)
ecs_event_t ecs_event(void);
ecs_observer_id_t ecs_observer_init(const ecs_observer_desc_t *desc);
void ecs_observer_enable(ecs_observer_id_t id);
void ecs_observer_disable(ecs_observer_id_t id);
void ecs_observer_trigger(
ecs_entity_t entity,
ecs_event_t event,
const void *trigger_data
);#include <siecs.h>
#define ecs_observer(...)
ecs_event_t ecs_event(void);
ecs_observer_id_t ecs_observer_init(const ecs_observer_desc_t *desc);
void ecs_observer_enable(ecs_observer_id_t id);
void ecs_observer_disable(ecs_observer_id_t id);
void ecs_observer_trigger(
ecs_entity_t entity,
ecs_event_t event,
const void *trigger_data
);typedef struct {
ecs_entity_t entity;
ecs_event_t event;
uintptr_t user_data;
const void *trigger_data;
} ecs_observer_event_t;#include <siecs.h>
typedef struct {
ecs_entity_t entity;
ecs_event_t event;
uintptr_t user_data;
const void *trigger_data;
} ecs_observer_event_t;typedef struct {
ecs_event_t on;
ecs_query_desc_t query;
ecs_observer_callback_t callback;
uintptr_t user_data;
} ecs_observer_desc_t;#include <siecs.h>
typedef struct {
ecs_event_t on;
ecs_query_desc_t query;
ecs_observer_callback_t callback;
uintptr_t user_data;
} ecs_observer_desc_t;Observers are enabled by default. Disabled observers stay registered but do not receive events.
Modules
Section titled “Modules”ECS_MODULE_DECLARE(Name, { /* settings */ });
ECS_MODULE_DEFINE(Name);
ECS_MODULE_IMPORT(world, Name, { /* settings */ });#include <siecs.h>
ECS_MODULE_DECLARE(Name, { /* settings */ });
ECS_MODULE_DEFINE(Name);
ECS_MODULE_IMPORT(world, Name, { /* settings */ });ECS_MODULE_DECLARE(Name, ...) generates Name_props_t for the typed module
parameters and declares Name_import().
typedef void (*ecs_module_import_t)(const void *desc);
typedef struct {
const char *name;
ecs_module_id_t *id;
ecs_module_import_t import;
const void *desc;
uint32_t desc_size;
bool disabled;
} ecs_module_desc_t;#include <siecs.h>
typedef void (*ecs_module_import_t)(const void *desc);
typedef struct {
const char *name;
ecs_module_id_t *id;
ecs_module_import_t import;
const void *desc;
uint32_t desc_size;
bool disabled;
} ecs_module_desc_t;#define ecs_module(...)
ecs_module_id_t ecs_module_init(const ecs_module_desc_t *desc);
ecs_module_id_t ecs_module_find(const ecs_module_id_t *id);
void ecs_module_enable(ecs_module_id_t module);
void ecs_module_disable(ecs_module_id_t module);
bool ecs_module_is_enabled(const ecs_module_id_t module);#include <siecs.h>
#define ecs_module(...)
ecs_module_id_t ecs_module_init(const ecs_module_desc_t *desc);
ecs_module_id_t ecs_module_find(const ecs_module_id_t *id);
void ecs_module_enable(ecs_module_id_t module);
void ecs_module_disable(ecs_module_id_t module);
bool ecs_module_is_enabled(const ecs_module_id_t module);Modules capture components, systems, and observers registered during import. Enabling and disabling a module affects only captured systems and observers.
Relations
Section titled “Relations”ECS_RELATION_DECLARE(Name);
ECS_RELATION_DEFINE(Name, flags);
ecs_source(Name);#include <siecs.h>
ECS_RELATION_DECLARE(Name);
ECS_RELATION_DEFINE(Name, flags);
ecs_source(Name);ChildOf is declared by the public API and registered during world bootstrap.
It uses EcsRelationCascadeDelete.
Systems
Section titled “Systems”typedef enum {
EcsPreStart,
EcsStart,
EcsPostStart,
EcsOnLoad,
EcsPostLoad,
EcsPreUpdate,
EcsOnUpdate,
EcsPostUpdate,
EcsPreRender,
EcsOnRender,
EcsPostRender,
EcsPhaseCount,
} ecs_phase_t;#include <siecs.h>
typedef enum {
EcsPreStart,
EcsStart,
EcsPostStart,
EcsOnLoad,
EcsPostLoad,
EcsPreUpdate,
EcsOnUpdate,
EcsPostUpdate,
EcsPreRender,
EcsOnRender,
EcsPostRender,
EcsPhaseCount,
} ecs_phase_t;ecs_progress() runs enabled systems in phase order. EcsPreStart,
EcsStart, and EcsPostStart are run only by the first ecs_progress() call
for a world. Manual ecs_run_phase() calls still run any valid phase normally.
OnPreUpdate, OnUpdate, OnPostUpdate, and OnRender are compatibility
aliases for the matching Ecs* names.
typedef struct {
const char *name;
ecs_query_desc_t query;
void (*callback)(ecs_iter_t *);
ecs_phase_t phase;
ecs_system_id_t after[4];
bool disabled;
} ecs_system_desc_t;#include <siecs.h>
typedef struct {
const char *name;
ecs_query_desc_t query;
void (*callback)(ecs_iter_t *);
ecs_phase_t phase;
ecs_system_id_t after[4];
bool disabled;
} ecs_system_desc_t;#define ecs_system(...)
ecs_system_id_t ecs_system_init(const ecs_system_desc_t *desc);
bool ecs_progress(void);
void ecs_run_phase(ecs_phase_t phase);
void ecs_run_system(ecs_system_id_t system);
void ecs_system_enable(ecs_system_id_t system);
void ecs_system_disable(ecs_system_id_t system);#include <siecs.h>
#define ecs_system(...)
ecs_system_id_t ecs_system_init(const ecs_system_desc_t *desc);
bool ecs_progress(void);
void ecs_run_phase(ecs_phase_t phase);
void ecs_run_system(ecs_system_id_t system);
void ecs_system_enable(ecs_system_id_t system);
void ecs_system_disable(ecs_system_id_t system);after declares systems that must run first in the same phase. System id 0 is
reserved, so an empty after array is written as { 0 } or omitted. Dependency
cycles and cross-phase dependencies are debug assertion failures.
Example:
static void Move(ecs_iter_t *it) {
Position *p = ecs_field(it, 0);
Velocity *v = ecs_field(it, 1);
for (uint32_t i = 0; i < it->count; i++) {
p[i].x += v[i].x;
p[i].y += v[i].y;
}
}
ecs_system({
.name = "Move",
.phase = EcsOnUpdate,
.query = { .terms = { ecs_inout(Position), ecs_in(Velocity) } },
.callback = Move,
});
ecs_progress();#include <siecs.h>
static void Move(ecs_iter_t *it) {
Position *p = ecs_field(it, 0);
Velocity *v = ecs_field(it, 1);
for (uint32_t i = 0; i < it->count; i++) {
p[i].x += v[i].x;
p[i].y += v[i].y;
}
}
ecs_system({
.name = "Move",
.phase = EcsOnUpdate,
.query = { .terms = { ecs_inout(Position), ecs_in(Velocity) } },
.callback = Move,
});
ecs_progress();