diff --git a/assets/init.lua b/assets/init.lua index 2f0072c..2799fd6 100644 --- a/assets/init.lua +++ b/assets/init.lua @@ -39,5 +39,5 @@ else end localeSet(DUSK_LOCALE_EN_US) --- sceneSet('map') +sceneSet('scene/initial.dsf') -- mapLoad('map/testmap/testmap.dmf') \ No newline at end of file diff --git a/assets/scene/CMakeLists.txt b/assets/scene/CMakeLists.txt index 9424ff4..c58d25f 100644 --- a/assets/scene/CMakeLists.txt +++ b/assets/scene/CMakeLists.txt @@ -3,4 +3,4 @@ # This software is released under the MIT License. # https://opensource.org/licenses/MIT -add_asset(SCRIPT map.lua) \ No newline at end of file +add_asset(SCRIPT initial.lua) \ No newline at end of file diff --git a/assets/scene/initial.lua b/assets/scene/initial.lua new file mode 100644 index 0000000..8893b65 --- /dev/null +++ b/assets/scene/initial.lua @@ -0,0 +1 @@ +print('Initial scene') \ No newline at end of file diff --git a/assets/scene/map.lua b/assets/scene/map.lua deleted file mode 100644 index ed42a51..0000000 --- a/assets/scene/map.lua +++ /dev/null @@ -1 +0,0 @@ --- Map Scene \ No newline at end of file diff --git a/src/error/error.c b/src/error/error.c index 4339ca4..45b3d63 100644 --- a/src/error/error.c +++ b/src/error/error.c @@ -108,13 +108,15 @@ errorret_t errorChainImpl( return retval; } -void errorCatch(const errorret_t retval) { +void errorCatch(errorret_t retval) { if(retval.code == ERROR_OK) return; assertNotNull(retval.state, "Error state cannot be NULL"); assertNotNull(retval.state->message, "Message cannot be NULL"); + // Clear the error state memoryFree((void*)retval.state->message); + retval.state->code = ERROR_OK; } errorret_t errorPrint(const errorret_t retval) { diff --git a/src/error/error.h b/src/error/error.h index 0ab8a69..ccd4c84 100644 --- a/src/error/error.h +++ b/src/error/error.h @@ -78,7 +78,7 @@ errorret_t errorChainImpl( * * @param retval The return value containing the error state. */ -void errorCatch(const errorret_t retval); +void errorCatch(errorret_t retval); /** * Prints the error state to the console. diff --git a/src/scene/scene.c b/src/scene/scene.c index 7e4edde..9b98311 100644 --- a/src/scene/scene.c +++ b/src/scene/scene.c @@ -5,80 +5,63 @@ #include "scene.h" #include "assert/assert.h" -#include "util/string.h" +#include "util/memory.h" -const scene_t SCENES[] = { -}; - -uint_fast8_t SCENE_CURRENT = 0xFF; +scene_t SCENE; errorret_t sceneInit(void) { - // Initialize the scene subsystem here + memoryZero(&SCENE, sizeof(scene_t)); + + errorChain(scriptContextInit(&SCENE.scriptContext)); errorOk(); } void sceneUpdate(void) { - const scene_t *current = sceneGetCurrent(); - if(current && current->update) { - current->update(); + if(!scriptContextHasFunc(&SCENE.scriptContext, "sceneUpdate")) { + return; } + + errorret_t err = scriptContextCallFunc( + &SCENE.scriptContext, "sceneUpdate", NULL, 0, NULL + ); + errorCatch(errorPrint(err)); } void sceneRender(void) { - const scene_t *current = sceneGetCurrent(); - - if(current && current->render) { - current->render(); + if(!scriptContextHasFunc(&SCENE.scriptContext, "sceneRender")) { + return; } + + errorret_t err = scriptContextCallFunc( + &SCENE.scriptContext, "sceneRender", NULL, 0, NULL + ); + errorCatch(errorPrint(err)); } -void sceneDispose(void) { - const scene_t *current = sceneGetCurrent(); - - if(current && current->dispose) { - current->dispose(); - } -} - -errorret_t sceneSet(const scene_t *scene) { - sceneDispose(); - - if(scene) { - SCENE_CURRENT = (uint_fast8_t)(scene - SCENES); - - assertTrue( - SCENE_CURRENT < sizeof(SCENES) / sizeof(scene_t), - "Invalid scene index." +errorret_t sceneSet(const char_t *script) { + // Cleanup old script context. + if(scriptContextHasFunc(&SCENE.scriptContext, "sceneDispose")) { + errorret_t err = scriptContextCallFunc( + &SCENE.scriptContext, "sceneDispose", NULL, 0, NULL ); - - if(scene->init) { - errorret_t err = scene->init(); - if(err.code != ERROR_OK) SCENE_CURRENT = 0xFF; - errorChain(err); - } - } else { - SCENE_CURRENT = 0xFF; + errorCatch(errorPrint(err)); } + scriptContextDispose(&SCENE.scriptContext); + + // Create a new script context. + errorChain(scriptContextInit(&SCENE.scriptContext)); + errorChain(scriptContextExecFile(&SCENE.scriptContext, script)); errorOk(); } -const scene_t* sceneGetCurrent(void) { - if(SCENE_CURRENT == 0xFF) return NULL; - - assertTrue( - SCENE_CURRENT < sizeof(SCENES) / sizeof(scene_t), - "Invalid current scene index." - ); - - return &SCENES[SCENE_CURRENT]; -} - -const scene_t* sceneGetByName(const char_t *name) { - for(uint_fast8_t i = 0; i < sizeof(SCENES) / sizeof(scene_t); i++) { - if(stringCompare(SCENES[i].name, name) == 0) { - return &SCENES[i]; - } +void sceneDispose(void) { + if(scriptContextHasFunc(&SCENE.scriptContext, "sceneDispose")) { + errorret_t err = scriptContextCallFunc( + &SCENE.scriptContext, "sceneDispose", NULL, 0, NULL + ); + errorCatch(errorPrint(err)); } - return NULL; + + scriptContextDispose(&SCENE.scriptContext); } \ No newline at end of file diff --git a/src/scene/scene.h b/src/scene/scene.h index 412df8b..d766f07 100644 --- a/src/scene/scene.h +++ b/src/scene/scene.h @@ -6,18 +6,13 @@ */ #pragma once -#include "error/error.h" +#include "script/scriptcontext.h" typedef struct { - const char_t *name; - errorret_t (*init)(void); - void (*update)(void); - void (*render)(void); - void (*dispose)(void); + scriptcontext_t scriptContext; } scene_t; -extern const scene_t SCENES[]; -extern uint_fast8_t SCENE_CURRENT; +extern scene_t SCENE; /** * Initialize the scene subsystem. @@ -34,30 +29,14 @@ void sceneUpdate(void); */ void sceneRender(void); +/** + * Set the current scene by script name. + * + * @param script The script name of the scene to set. + */ +errorret_t sceneSet(const char_t *script); + /** * Dispose of the scene subsystem. */ -void sceneDispose(void); - -/** - * Set the current scene. - * - * @param sceneIndex The index of the scene to set. - * @return An error code indicating success or failure. - */ -errorret_t sceneSet(const scene_t *scene); - -/** - * Get the current scene. - * - * @return The current scene. - */ -const scene_t* sceneGetCurrent(void); - -/** - * Get a scene by its name. - * - * @param name The name of the scene. - * @return The scene with the given name, or NULL if not found. - */ -const scene_t* sceneGetByName(const char_t *name); \ No newline at end of file +void sceneDispose(void); \ No newline at end of file diff --git a/src/script/module/CMakeLists.txt b/src/script/module/CMakeLists.txt index 787abce..da274a2 100644 --- a/src/script/module/CMakeLists.txt +++ b/src/script/module/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2025 Dominic Masters +# Copyright (c) 2026 Dominic Masters # # This software is released under the MIT License. # https://opensource.org/licenses/MIT @@ -8,4 +8,6 @@ add_subdirectory(event) add_subdirectory(input) add_subdirectory(item) add_subdirectory(locale) -add_subdirectory(system) \ No newline at end of file +add_subdirectory(system) +add_subdirectory(scene) +add_subdirectory(time) \ No newline at end of file diff --git a/src/script/module/locale/modulelocale.c b/src/script/module/locale/modulelocale.c index a53311c..4f21668 100644 --- a/src/script/module/locale/modulelocale.c +++ b/src/script/module/locale/modulelocale.c @@ -48,6 +48,7 @@ int moduleLocaleSet(lua_State *L) { err = localeManagerSetLocale(locale); if(err.code != ERROR_OK) { luaL_error(L, "localeSet: Failed to set locale"); + errorCatch(errorPrint(err)); return 0; } diff --git a/src/script/module/modulescene.h b/src/script/module/modulescene.h deleted file mode 100644 index 6172698..0000000 --- a/src/script/module/modulescene.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "script/scriptcontext.h" -#include "scene/scene.h" - -int moduleSceneSetScene(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - assertTrue(lua_isstring(L, 1), "Expected string scene name"); - - const char *sceneName = luaL_checkstring(L, 1); - if(sceneName == NULL || sceneName[0] == '\0') { - luaL_error(L, "Scene name cannot be NULL"); - return 0; - } - - const scene_t *scene = sceneGetByName(sceneName); - if(scene == NULL) { - luaL_error(L, "Scene '%s' not found", sceneName); - return 0; - } - - errorret_t err = sceneSet(scene); - if(err.code != ERROR_OK) { - luaL_error(L, "Failed to set scene '%s'", sceneName); - return 0; - } - return 0; -} - -void moduleScene(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be NULL"); - - scriptContextRegFunc(ctx, "sceneSet", moduleSceneSetScene); -} \ No newline at end of file diff --git a/src/script/module/scene/CMakeLists.txt b/src/script/module/scene/CMakeLists.txt new file mode 100644 index 0000000..9b09983 --- /dev/null +++ b/src/script/module/scene/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 + modulescene.c +) \ No newline at end of file diff --git a/src/script/module/scene/modulescene.c b/src/script/module/scene/modulescene.c new file mode 100644 index 0000000..d3f38bd --- /dev/null +++ b/src/script/module/scene/modulescene.c @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "modulescene.h" +#include "assert/assert.h" +#include "scene/scene.h" + +void moduleScene(scriptcontext_t *ctx) { + assertNotNull(ctx, "Script context cannot be NULL"); + + scriptContextRegFunc(ctx, "sceneSet", moduleSceneSet); +} + +int moduleSceneSet(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + // Need string + if (!lua_isstring(L, 1)) { + luaL_error(L, "sceneSet requires a string argument"); + return 0; + } + + const char_t *script = lua_tostring(L, 1); + + errorret_t err = sceneSet(script); + if(err.code != ERROR_OK) { + luaL_error(L, "Failed to set scene"); + errorCatch(errorPrint(err)); + return 0; + } + + return 0; +} \ No newline at end of file diff --git a/src/script/module/scene/modulescene.h b/src/script/module/scene/modulescene.h new file mode 100644 index 0000000..773d05f --- /dev/null +++ b/src/script/module/scene/modulescene.h @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "script/scriptcontext.h" + +/** + * Register the scene module within the given script context. + * + * @param ctx The script context to register the module in. + */ +void moduleScene(scriptcontext_t *ctx); + +/** + * Lua binding for sceneSet function. + * + * @param L The Lua state. + * @return int Number of return values on the Lua stack. + */ +int moduleSceneSet(lua_State *L); \ No newline at end of file diff --git a/src/script/module/time/CMakeLists.txt b/src/script/module/time/CMakeLists.txt new file mode 100644 index 0000000..8fd83bc --- /dev/null +++ b/src/script/module/time/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 + moduletime.c +) \ No newline at end of file diff --git a/src/script/module/moduletime.h b/src/script/module/time/moduletime.c similarity index 89% rename from src/script/module/moduletime.h rename to src/script/module/time/moduletime.c index f0d0251..a739d25 100644 --- a/src/script/module/moduletime.h +++ b/src/script/module/time/moduletime.c @@ -5,10 +5,19 @@ * https://opensource.org/licenses/MIT */ -#pragma once -#include "script/scriptcontext.h" -#include "time/time.h" -#include "util/string.h" +#include "moduletime.h" +#include "assert/assert.h" +#include "script/scriptstruct.h" + +void moduleTime(scriptcontext_t *ctx) { + assertNotNull(ctx, "Script context cannot be NULL"); + + // Script structure + scriptStructRegister(ctx, "time_mt", moduleTimeGetter, NULL); + + // Register struct + scriptStructPush(ctx, "time_mt", "TIME", &TIME); +} void moduleTimeGetter( const scriptcontext_t *context, @@ -25,14 +34,4 @@ void moduleTimeGetter( outValue->value.floatValue = TIME.time; return; } -} - -void moduleTime(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be NULL"); - - // Script structure - scriptStructRegister(ctx, "time_mt", moduleTimeGetter, NULL); - - // Register struct - scriptStructPush(ctx, "time_mt", "TIME", &TIME); } \ No newline at end of file diff --git a/src/script/module/time/moduletime.h b/src/script/module/time/moduletime.h new file mode 100644 index 0000000..360aa51 --- /dev/null +++ b/src/script/module/time/moduletime.h @@ -0,0 +1,33 @@ +/** + * 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" +#include "util/string.h" + +/** + * Registers the time module within the given script context. + * + * @param ctx The script context to register the module in. + */ +void moduleTime(scriptcontext_t *ctx); + +/** + * Getter function for the TIME struct in scripts. + * + * @param context The script context. + * @param key The key being accessed. + * @param structPtr Pointer to the struct instance. + * @param outValue Output parameter to store the retrieved value. + */ +void moduleTimeGetter( + const scriptcontext_t *context, + const char_t *key, + const void *structPtr, + scriptvalue_t *outValue +); \ No newline at end of file diff --git a/src/script/scriptcontext.c b/src/script/scriptcontext.c index 8f26064..673d5c1 100644 --- a/src/script/scriptcontext.c +++ b/src/script/scriptcontext.c @@ -155,6 +155,19 @@ errorret_t scriptContextCallFunc( errorOk(); } +bool_t scriptContextHasFunc( + scriptcontext_t *context, + const char_t *fnName +) { + assertNotNull(context, "Script context cannot be NULL"); + assertNotNull(fnName, "Function name cannot be NULL"); + + lua_getglobal(context->luaState, fnName); + bool_t isFunc = lua_isfunction(context->luaState, -1); + lua_pop(context->luaState, 1); + return isFunc; +} + errorret_t scriptContextExec(scriptcontext_t *context, const char_t *script) { assertNotNull(context, "Script context cannot be NULL"); assertNotNull(script, "Script cannot be NULL"); diff --git a/src/script/scriptcontext.h b/src/script/scriptcontext.h index bfbfbfe..d043ae0 100644 --- a/src/script/scriptcontext.h +++ b/src/script/scriptcontext.h @@ -74,6 +74,18 @@ errorret_t scriptContextCallFunc( scriptvalue_t *retValue ); +/** + * Checks if a Lua function exists within a script context. + * + * @param context The script context to use. + * @param fnName The name of the Lua function to check. + * @return true if the function exists, false otherwise. + */ +bool_t scriptContextHasFunc( + scriptcontext_t *context, + const char_t *fnName +); + /** * Execute a script within a script context. * diff --git a/src/script/scriptmodule.c b/src/script/scriptmodule.c index d30a772..3bdf733 100644 --- a/src/script/scriptmodule.c +++ b/src/script/scriptmodule.c @@ -9,10 +9,10 @@ #include "script/module/system/modulesystem.h" #include "script/module/input/moduleinput.h" #include "script/module/moduleplatform.h" -#include "script/module/modulescene.h" +#include "script/module/scene/modulescene.h" #include "script/module/item/moduleitem.h" #include "script/module/locale/modulelocale.h" -#include "script/module/moduletime.h" +#include "script/module/time/moduletime.h" #include "script/module/event/moduleevent.h" #include "util/string.h"