132 lines
4.8 KiB
C
132 lines
4.8 KiB
C
#ifndef EVENTS_H
|
|
#define EVENTS_H
|
|
|
|
#include "ui.h"
|
|
|
|
// Source id for events/writes originating from C. Container ids are nonzero
|
|
// (load_container rejects 0), so 0 is free to mean "the engine".
|
|
#define EVENT_SOURCE_ENGINE 0
|
|
|
|
// Names under "engine." can only be emitted by C; app.emit rejects them.
|
|
// Property writes announce themselves as "engine.changed.<property>".
|
|
#define EVENT_ENGINE_PREFIX "engine."
|
|
#define EVENT_CHANGED_PREFIX "engine.changed."
|
|
|
|
// Dispatched directly (never queued) once per drain after the queue is
|
|
// exhausted, so handlers reliably run after every change event of the
|
|
// frame — the coalescing point for dirty-flag subscribers. Events emitted
|
|
// by its handlers queue for the next frame.
|
|
#define EVENT_FRAME "engine.frame"
|
|
|
|
// Max events processed per drain; hitting it means a handler cycle is
|
|
// endlessly re-emitting, so the remainder is dumped to stderr and dropped.
|
|
#define EVENT_DRAIN_MAX 1024
|
|
|
|
typedef enum PropertyTypeEnum {
|
|
PROPERTY_NUMBER,
|
|
PROPERTY_STRING,
|
|
PROPERTY_BOOL,
|
|
} PropertyType;
|
|
|
|
typedef struct PropertyStruct {
|
|
char* name;
|
|
PropertyType type;
|
|
union {
|
|
double number;
|
|
char* string; // owned; NULL until first set
|
|
bool boolean;
|
|
} value;
|
|
} Property;
|
|
|
|
// C subscriber. The event's packed args table is on the Lua stack at
|
|
// args_index (t[1..t.n]); it must still be there when the handler returns.
|
|
typedef void (*EventHandler)(
|
|
void* userdata,
|
|
const char* event,
|
|
uint32_t source,
|
|
lua_State* L,
|
|
int args_index);
|
|
|
|
typedef struct EventSubscriptionStruct {
|
|
char* event;
|
|
// Registry ref of the script this subscription was made from, restored as
|
|
// the ambient "current script" before invoking a Lua handler — so
|
|
// ui.create_overlay called from inside it attributes correctly. Not used
|
|
// for lifecycle: subscriptions currently live for the process, since
|
|
// nothing unloads a script (only overlays, which are a separate
|
|
// lifecycle — see events-design memory).
|
|
int script_env;
|
|
int lua_ref; // handler function ref, LUA_NOREF for C handlers
|
|
EventHandler handler; // NULL for Lua handlers
|
|
void* userdata;
|
|
// Removal during a drain marks instead of compacting so in-flight
|
|
// iteration stays valid; compaction happens when the drain finishes
|
|
uint8_t dead;
|
|
} EventSubscription;
|
|
|
|
typedef struct QueuedEventStruct {
|
|
char* name;
|
|
uint32_t source;
|
|
int args_ref; // registry ref to the packed args table
|
|
} QueuedEvent;
|
|
|
|
struct EventBusStruct {
|
|
lua_State* L;
|
|
|
|
EventSubscription* subs;
|
|
uint32_t sub_count;
|
|
uint32_t sub_cap;
|
|
|
|
QueuedEvent* queue;
|
|
uint32_t queue_count;
|
|
uint32_t queue_cap;
|
|
|
|
Property* properties;
|
|
uint32_t property_count;
|
|
uint32_t property_cap;
|
|
|
|
bool draining;
|
|
};
|
|
|
|
// Registers the `app` global (emit/subscribe/get/set) in the Lua state
|
|
VkResult event_bus_init(EventBus* bus, lua_State* L);
|
|
|
|
// Frees subs/queue/properties. Must run while bus->L is still open - it
|
|
// luaL_unrefs each subscription's handler and each queued event's args
|
|
// table out of the registry.
|
|
void event_bus_destroy(EventBus* bus);
|
|
|
|
// Pops nargs values off the top of the Lua stack into the event's packed
|
|
// args and appends to the queue. Never dispatches; the queue drains once
|
|
// per frame from the top level.
|
|
VkResult event_emit(EventBus* bus, const char* name, uint32_t source, int nargs);
|
|
|
|
// Subscribes a C handler; Lua handlers subscribe via app.subscribe
|
|
VkResult event_subscribe(EventBus* bus, const char* name, EventHandler handler, void* userdata);
|
|
|
|
// Dispatches queued events in emit order, including events emitted by
|
|
// handlers during the drain, up to EVENT_DRAIN_MAX
|
|
void event_bus_drain(EventBus* bus, UIContext* ui, RenderContext* gpu, double delta_time);
|
|
|
|
VkResult event_property_register(EventBus* bus, const char* name, PropertyType type);
|
|
|
|
// Direct read access; NULL if unregistered
|
|
Property* event_property(EventBus* bus, const char* name);
|
|
|
|
// Setters no-op when the value is unchanged; otherwise they store the value
|
|
// and emit engine.changed.<name> with the new value as the single argument.
|
|
// Emission is unconditional on real changes regardless of who wrote.
|
|
VkResult event_property_set_number(EventBus* bus, const char* name, double value, uint32_t source);
|
|
VkResult event_property_set_string(EventBus* bus, const char* name, const char* value, uint32_t source);
|
|
VkResult event_property_set_bool(EventBus* bus, const char* name, bool value, uint32_t source);
|
|
|
|
// Arg accessors for C EventHandler bodies
|
|
int event_arg_count(lua_State* L, int args_index);
|
|
double event_arg_number(lua_State* L, int args_index, int i);
|
|
bool event_arg_bool(lua_State* L, int args_index, int i);
|
|
// Returned pointer is anchored by the args table; valid until the drain
|
|
// releases the event
|
|
const char* event_arg_string(lua_State* L, int args_index, int i);
|
|
|
|
#endif
|