From 9b73f1717f4824b4c5f9bbd74a31497e60589b05 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Tue, 27 Jan 2026 10:41:32 -0600 Subject: [PATCH] Event --- src/CMakeLists.txt | 1 + src/event/CMakeLists.txt | 10 ++++ src/event/event.c | 106 +++++++++++++++++++++++++++++++++ src/event/event.h | 79 ++++++++++++++++++++++++ src/script/module/moduletime.h | 29 +++++++++ src/script/scriptmodule.c | 2 + 6 files changed, 227 insertions(+) create mode 100644 src/event/CMakeLists.txt create mode 100644 src/event/event.c create mode 100644 src/event/event.h create mode 100644 src/script/module/moduletime.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 84ef3e2..409cef9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -55,6 +55,7 @@ add_subdirectory(debug) add_subdirectory(display) add_subdirectory(engine) add_subdirectory(error) +add_subdirectory(event) add_subdirectory(input) add_subdirectory(item) add_subdirectory(locale) diff --git a/src/event/CMakeLists.txt b/src/event/CMakeLists.txt new file mode 100644 index 0000000..a959647 --- /dev/null +++ b/src/event/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2026 Dominic Masters +# +# This software is released under the MIT License. +# https://opensource.org/licenses/MIT + +# Sources +target_sources(${DUSK_LIBRARY_TARGET_NAME} + PUBLIC + event.c +) \ No newline at end of file diff --git a/src/event/event.c b/src/event/event.c new file mode 100644 index 0000000..6d79d4a --- /dev/null +++ b/src/event/event.c @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "event.h" +#include "assert/assert.h" +#include "util/memory.h" + +void eventInit( + event_t *event, + eventlistener_t *array, + const uint16_t maxListeners +) { + assertNotNull(event, "Event cannot be NULL"); + assertNotNull(array, "Listener array cannot be NULL"); + assertTrue(maxListeners > 0, "Max listeners must be greater than 0"); + + memoryZero(event, sizeof(event_t)); + + event->listenerArray = array; + event->maxListeners = maxListeners; +} + +eventsub_t eventSubscribe( + event_t *event, + const eventcallback_t callback, + const void *user +) { + assertNotNull(event, "Event cannot be NULL"); + assertNotNull(callback, "Callback cannot be NULL"); + assertTrue( + event->listenerCount < event->maxListeners, + "Maximum number of listeners reached" + ); + + // Gen a new ID + eventsub_t id = event->nextId++; + // Did we wrap? + assertTrue(event->nextId != 0, "Event subscription ID overflow"); + + // Append listener + eventlistener_t *listener = &event->listenerArray[event->listenerCount++]; + memoryZero(listener, sizeof(eventlistener_t)); + listener->callback = callback; + listener->user = (void*)user; + listener->id = id; + + return id; +} + +void eventUnsubscribe(event_t *event, const eventsub_t id) { + assertNotNull(event, "Event cannot be NULL"); + assertFalse(event->isInvoking, "Cannot unsubscribe while invoking event"); + + if(event->listenerCount == 0) return; + + // Find listener + uint16_t index = 0; + do { + if(event->listenerArray[index].id == id) { + // Found it, remove by swapping with last and reducing count + event->listenerArray[index] = event->listenerArray[--event->listenerCount]; + return; + } + index++; + } while(index < event->listenerCount); + + // Did we find it? + if(index == event->listenerCount) return; + + // Shift remaining listeners down (if any) + if(index < event->listenerCount - 1) { + memoryMove( + &event->listenerArray[index], + &event->listenerArray[index + 1], + sizeof(eventlistener_t) * (event->listenerCount - index - 1) + ); + } + + event->listenerCount--; +} + +void eventInvoke(event_t *event, const void *eventParams) { + assertNotNull(event, "Event cannot be NULL"); + + if(event->listenerCount == 0) return; + + event->isInvoking = true; + + uint16_t i = 0; + eventdata_t data ={ + .event = event, + .eventParams = eventParams, + }; + + do { + data.user = event->listenerArray[i].user; + event->listenerArray[i].callback(&data); + i++; + } while(i < event->listenerCount); + + event->isInvoking = false; +} \ No newline at end of file diff --git a/src/event/event.h b/src/event/event.h new file mode 100644 index 0000000..9c065ce --- /dev/null +++ b/src/event/event.h @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" + +typedef struct event_s event_t; + +typedef struct { + void *user; + const void *eventParams; + const event_t *event; +} eventdata_t; + +typedef void (*eventcallback_t)(eventdata_t *data); + +typedef struct { + eventcallback_t callback; + void *user; + uint16_t id; +} eventlistener_t; + +typedef uint16_t eventsub_t; + +typedef struct event_s { + eventlistener_t *listenerArray; + uint16_t listenerCount; + uint16_t maxListeners; + eventsub_t nextId; + + bool_t isInvoking; +} event_t; + +/** + * Initialize an event structure. + * + * @param event The event to initialize. + * @param array The array to hold event listeners. + * @param maxListeners The maximum number of listeners. + */ +void eventInit( + event_t *event, + eventlistener_t *array, + const uint16_t maxListeners +); + +/** + * Subscribe to an event. + * + * @param event The event to subscribe to. + * @param callback The callback function to invoke. + * @param user User data to pass to the callback. + * @return The subscription ID, used to unsubscribe later. + */ +eventsub_t eventSubscribe( + event_t *event, + const eventcallback_t callback, + const void *user +); + +/** + * Unsubscribe from an event. + * + * @param event The event to unsubscribe from. + * @param subscription The subscription ID to remove. + */ +void eventUnsubscribe(event_t *event, const eventsub_t subscription); + +/** + * Invoke an event, calling all subscribed listeners. + * + * @param event The event to invoke. + * @param eventParams Parameters to pass to the event listeners. + */ +void eventInvoke(event_t *event, const void *eventParams); \ No newline at end of file diff --git a/src/script/module/moduletime.h b/src/script/module/moduletime.h new file mode 100644 index 0000000..c98bb85 --- /dev/null +++ b/src/script/module/moduletime.h @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "script/scriptcontext.h" +#include "time/time.h" + +int moduleTimeGetDelta(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + lua_pushnumber(L, TIME.delta); + return 1; +} + +int moduleTimeGetTime(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + lua_pushnumber(L, TIME.time); + return 1; +} + +void moduleTime(scriptcontext_t *ctx) { + assertNotNull(ctx, "Script context cannot be NULL"); + + scriptContextRegFunc(ctx, "timeGetDelta", moduleTimeGetDelta); + scriptContextRegFunc(ctx, "timeGetTime", moduleTimeGetTime); +} \ No newline at end of file diff --git a/src/script/scriptmodule.c b/src/script/scriptmodule.c index c76bb35..de89970 100644 --- a/src/script/scriptmodule.c +++ b/src/script/scriptmodule.c @@ -12,6 +12,7 @@ #include "script/module/modulescene.h" #include "script/module/moduleitem.h" #include "script/module/modulelocale.h" +#include "script/module/moduletime.h" const scriptmodule_t SCRIPT_MODULE_LIST[] = { { .name = "system", .callback = moduleSystem }, @@ -20,6 +21,7 @@ const scriptmodule_t SCRIPT_MODULE_LIST[] = { { .name = "scene", .callback = moduleScene }, { .name = "item", .callback = moduleItem }, { .name = "locale", .callback = moduleLocale }, + { .name = "time", .callback = moduleTime }, }; #define SCRIPT_MODULE_COUNT ( \