Resources
Resources are typed values stored once per world. Use them for state that is unique to the world, not attached to each entity: frame time, input state, renderer handles, asset registries, shared config, or global simulation settings.
Resources have their own ecs_resource_t ids. They do not consume component
ids, they are not added to an entity, they are not query terms, and they do not
consume an ecs_field() slot.
Declare A Resource
Section titled “Declare A Resource”Resources are declared once and stored per world:
ECS_RESOURCE_DECLARE(Time, { float dt; float elapsed;});
ECS_RESOURCE_DEFINE(Time);ECS_RESOURCE_REGISTER(world, Time);struct Time { float dt; };ecs::set_resource(Time{ .dt = 0.016f });The resource macros intentionally mirror component macros, but resources are registered in a dedicated resource registry.
Set And Read
Section titled “Set And Read”ecs_set_resource() creates or replaces the resource value:
ecs_set_resource(Time, { .dt = 0.016f, .elapsed = 0.0f,});ecs::set_resource(Time{ .dt = 0.016f, .elapsed = 0.0f });Use ecs_get_resource() when the resource must exist:
Time *time = ecs_get_resource(Time);time->elapsed += time->dt;auto &time = ecs::resource<Time>();time.elapsed += time.dt;Use ecs_get_resource_read() when the caller only needs read access:
const Time *time = ecs_get_resource_read(Time);const auto &time = ecs::resource<const Time>();If absence is valid, use the nullable helpers:
Time *time = ecs_try_get_resource(Time);if (time != NULL) { time->elapsed += time->dt;}
const Time *read_time = ecs_try_get_resource_read(Time);if (auto *time = ecs::try_resource<Time>()) { time->elapsed += time->dt;}
const auto *read_time = ecs::try_resource<const Time>();ecs_get_resource() and ecs_get_resource_read() assert when the resource does not
exist. The try variants return NULL.
Presence And Removal
Section titled “Presence And Removal”Check whether a resource exists with ecs_has_resource():
if (!ecs_has_resource(Time)) { ecs_set_resource(Time, { .dt = 0.0f, .elapsed = 0.0f, });}if (!ecs::has_resource<Time>()) { ecs::set_resource(Time{ .dt = 0.0f, .elapsed = 0.0f });}Remove it with ecs_remove_resource():
ecs_remove_resource(Time);ecs::remove_resource<Time>();Removing a missing resource is a no-op.
Use Resources In C Systems
Section titled “Use Resources In C Systems”In C, systems receive an ecs_iter_t *. Read resources from it->world before
the entity loop:
static void move_system(ecs_iter_t *it) { const Time *time = ecs_get_resource_read(it->world, Time); Position *positions = ecs_field(it, 0); const Velocity *velocities = ecs_field(it, 1);
for (uint32_t i = 0; i < it->count; i++) { positions[i].x += velocities[i].x * time->dt; positions[i].y += velocities[i].y * time->dt; }}
ecs_system({ .name = "Move", .phase = EcsOnUpdate, .query = { .terms = { ecs_inout(Position), ecs_in(Velocity) }, }, .callback = move_system,});ecs::system("Move").each([]( ecs::res<const Time> time, Position &position, const Velocity &velocity) { position.x += velocity.x * time->dt; position.y += velocity.y * time->dt;});The resource is not part of the query. The system above matches entities with
Position and Velocity; it does not require entities to have Time.
Id-Based API
Section titled “Id-Based API”Typed helpers are wrappers around the id-based API:
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>
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);This is useful for generic module code:
ecs_resource_t time_id = ecs_id(Time);
if (ecs_has_resource_rid(time_id)) {
const Time *time = ecs_resource_rid(time_id);
/* use time */
}#include <siecs.h>
ecs_resource_t time_id = ecs_id(Time);
if (ecs_has_resource_rid(time_id)) {
const Time *time = ecs_resource_rid(time_id);
/* use time */
}Resources have dedicated resource hooks:
on_setruns whenecs_set_resource()writes a value.on_removeruns whenecs_remove_resource()removes the value.on_removealso runs duringecs_fini()for resources still present in the world.
Hooks receive only the world and the resource value pointer.
static void on_time_set(const void *data) {
(void)world;
const Time *time = data;
if (time->dt < 0.0f) {
/* reject or record invalid data */
}
}#include <siecs.h>
static void on_time_set(const void *data) {
(void)world;
const Time *time = data;
if (time->dt < 0.0f) {
/* reject or record invalid data */
}
}Performance Notes
Section titled “Performance Notes”Resource lookup is a direct index by ecs_resource_t, so access is O(1). The
value is stored once in the world and is independent from table iteration.
For hot C systems, resolve the resource once before the loop over it->count,
then reuse the pointer for every entity in the batch.