Compare commits

...

5 Commits

Author SHA1 Message Date
f39b2060a8 iuno just screwing around tbh
Some checks failed
Build Dusk / build-linux (push) Failing after 1m5s
Build Dusk / build-psp (push) Failing after 1m24s
2025-12-24 10:44:53 +10:00
aed202ebf9 Add include()
Some checks failed
Build Dusk / build-linux (push) Successful in 1m16s
Build Dusk / build-psp (push) Failing after 1m14s
2025-12-24 09:41:05 +10:00
a495179e5f Prog
Some checks failed
Build Dusk / build-linux (push) Successful in 1m19s
Build Dusk / build-psp (push) Failing after 1m36s
2025-12-05 14:41:13 -06:00
4e1b404820 Add script context
Some checks failed
Build Dusk / build-linux (push) Successful in 1m41s
Build Dusk / build-psp (push) Failing after 2m36s
2025-12-04 20:57:12 -06:00
8c74ee31e0 Add lua diff
All checks were successful
Build Dusk / build-linux (push) Successful in 1m51s
Build Dusk / build-psp (push) Successful in 2m2s
2025-12-04 00:39:09 -06:00
32 changed files with 651 additions and 179 deletions

View File

@@ -4,3 +4,5 @@
# https://opensource.org/licenses/MIT
add_asset(SCRIPT test.lua)
add_subdirectory(scene)

5
assets/script/init.lua Normal file
View File

@@ -0,0 +1,5 @@
print('Init')
-- Load map scene
setScene('map')
setMap()

View File

@@ -0,0 +1,4 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT

View File

@@ -1 +0,0 @@
print("Test Lua script")

View File

@@ -1,59 +0,0 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
if(NOT TARGET lua)
message(STATUS "Looking for Lua...")
set(LUA_FOUND FALSE CACHE INTERNAL "Lua found")
set(LUA_DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/_lua")
set(LUA_SEARCH_ROOTS
"${LUA_ROOT}"
"$ENV{LUADEV}"
"$ENV{HOME}/luadev"
"/usr/local/luadev"
"/opt/luadev"
"/usr/luadev"
"${LUA_DOWNLOAD_DIR}/luadev"
)
foreach(root IN LISTS LUA_SEARCH_ROOTS)
list(APPEND LUA_BIN_HINTS "${root}/bin")
list(APPEND LUA_INCLUDE_HINTS "${root}/include")
list(APPEND LUA_LIB_HINTS "${root}/lib")
endforeach()
# Find Lua interpreter
find_program(LUA_EXECUTABLE NAMES lua HINTS ${LUA_BIN_HINTS})
# Find Lua headers and library
find_path(LUA_INCLUDE_DIR lua.h HINTS ${LUA_INCLUDE_HINTS})
find_library(LUA_LIBRARY NAMES lua HINTS ${LUA_LIB_HINTS})
# If not found, use FetchContent to download and build Lua
if(NOT LUA_EXECUTABLE OR NOT LUA_INCLUDE_DIR OR NOT LUA_LIBRARY)
message(STATUS "Lua not found in system paths. Using FetchContent to download and build Lua.")
include(FetchContent)
FetchContent_Declare(
lua
GIT_REPOSITORY https://github.com/lua/lua.git
GIT_TAG v5.4.6 # Change to desired version
)
FetchContent_MakeAvailable(lua)
# Try to locate built Lua
set(LUA_INCLUDE_DIR "${lua_SOURCE_DIR}")
set(LUA_LIBRARY "${lua_BINARY_DIR}/liblua.a")
set(LUA_EXECUTABLE "${lua_BINARY_DIR}/lua")
endif()
if(LUA_EXECUTABLE AND LUA_INCLUDE_DIR AND LUA_LIBRARY)
set(LUA_FOUND TRUE CACHE INTERNAL "Lua found")
add_library(lua INTERFACE IMPORTED)
set_target_properties(lua PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${LUA_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES "${LUA_LIBRARY}"
)
message(STATUS "Lua found: ${LUA_EXECUTABLE}")
endif()
endif()

View File

@@ -5,7 +5,17 @@
find_package(cglm REQUIRED)
find_package(libzip REQUIRED)
find_package(lua REQUIRED)
find_package(Lua REQUIRED)
if(Lua_FOUND AND NOT TARGET Lua::Lua)
add_library(Lua::Lua INTERFACE IMPORTED)
set_target_properties(
Lua::Lua
PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${LUA_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES "${LUA_LIBRARIES}"
)
endif()
# Libs
target_link_libraries(${DUSK_TARGET_NAME}
@@ -13,8 +23,8 @@ target_link_libraries(${DUSK_TARGET_NAME}
m
cglm
zip
lua
pthread
Lua::Lua
)
# Includes

View File

@@ -12,9 +12,7 @@ void debugPrint(const char_t *message, ...) {
va_start(args, message);
vprintf(message, args);
va_end(args);
// For the time being just use standard printing functions.
printf(message, args);
fflush(stdout);
#if PSP
FILE *file = fopen("ms0:/PSP/GAME/Dusk/debug.log", "a");

View File

@@ -8,7 +8,7 @@ ENTITY_DIR_WEST = 1
ENTITY_DIR_EAST = 2
ENTITY_DIR_NORTH = 3
ENTITY_COUNT = 256
ENTITY_COUNT = 128
ENTITY_TYPE_NULL = 0
ENTITY_TYPE_PLAYER = 1

View File

@@ -32,16 +32,16 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
inputInit();
errorChain(assetInit());
errorChain(localeManagerInit());
errorChain(scriptManagerInit());
errorChain(displayInit());
errorChain(uiInit());
errorChain(rpgInit());
errorChain(sceneManagerInit());
errorChain(scriptManagerInit());
// scriptManagerExec(
// "print('Hello from Lua!')\n"
// "luaCallable()\n"
// );
// Run the initial script.
errorChain(scriptContextInit(&ENGINE.mainScriptContext));
errorChain(scriptContextExecFile(&ENGINE.mainScriptContext, "script/test.dsf"));
scriptContextDispose(&ENGINE.mainScriptContext);
errorOk();
}
@@ -55,7 +55,6 @@ errorret_t engineUpdate(void) {
sceneManagerUpdate();
errorChain(displayUpdate());
if(inputPressed(INPUT_ACTION_RAGEQUIT)) ENGINE.running = false;
errorOk();

View File

@@ -8,11 +8,13 @@
#pragma once
#include "display/display.h"// Important to be included first.
#include "error/error.h"
#include "script/scriptcontext.h"
typedef struct {
bool_t running;
int32_t argc;
const char_t **argv;
scriptcontext_t mainScriptContext;
} engine_t;
extern engine_t ENGINE;

View File

@@ -9,7 +9,8 @@
#include "cutscenewait.h"
#include "cutscenecallback.h"
#include "cutscenetext.h"
#include "cutscenecutscene.h"
typedef struct cutscene_s cutscene_t;
typedef enum {
CUTSCENE_ITEM_TYPE_NULL,
@@ -27,7 +28,7 @@ typedef struct cutsceneitem_s {
cutscenetext_t text;
cutscenecallback_t callback;
cutscenewait_t wait;
const cutscenecutscene_t cutscene;
const cutscene_t *cutscene;
};
} cutsceneitem_t;

View File

@@ -16,7 +16,7 @@ typedef struct map_s map_t;
typedef struct entity_s {
uint8_t id;
entitytype_t type;
entitytypedata_t;
entitytypedata_t data;
// Movement
entitydir_t direction;

View File

@@ -27,13 +27,13 @@ errorret_t rpgInit(void) {
rpgTextboxInit();
// TEST: Create some entities.
uint8_t entIndex = entityGetAvailable();
assertTrue(entIndex != 0xFF, "No available entity slots!.");
entity_t *ent = &ENTITIES[entIndex];
entityInit(ent, ENTITY_TYPE_PLAYER);
RPG_CAMERA.mode = RPG_CAMERA_MODE_FOLLOW_ENTITY;
RPG_CAMERA.followEntity.followEntityId = ent->id;
ent->position.x = 2, ent->position.y = 2;
// uint8_t entIndex = entityGetAvailable();
// assertTrue(entIndex != 0xFF, "No available entity slots!.");
// entity_t *ent = &ENTITIES[entIndex];
// entityInit(ent, ENTITY_TYPE_PLAYER);
// RPG_CAMERA.mode = RPG_CAMERA_MODE_FOLLOW_ENTITY;
// RPG_CAMERA.followEntity.followEntityId = ent->id;
// ent->position.x = 2, ent->position.y = 2;
// All Good!
errorOk();

View File

@@ -16,8 +16,7 @@ map_t MAP;
errorret_t mapInit() {
memoryZero(&MAP, sizeof(map_t));
// Init the default chunks. In future I'll probably make this based on where
// the player spawns in to save an initial mapSet.
// Init the first chunks.
chunkindex_t index = 0;
for(chunkunit_t z = 0; z < MAP_CHUNK_DEPTH; z++) {
for(chunkunit_t y = 0; y < MAP_CHUNK_HEIGHT; y++) {

View File

@@ -19,12 +19,6 @@ errorret_t sceneManagerInit(void) {
sceneManagerRegisterScene(&SCENE_TEST);
sceneManagerRegisterScene(&SCENE_MAP);
// Initial scene
scene_t *initial = sceneManagerGetSceneByName("map");
sceneManagerSetScene(initial);
if(initial->init) errorChain(initial->init(&SCENE_MANAGER.sceneData));
initial->flags |= SCENE_FLAG_INITIALIZED;
errorOk();
}

View File

@@ -9,7 +9,7 @@
#include "scene.h"
#include "scenedata.h"
#define SCENE_MANAGER_SCENE_COUNT_MAX 32
#define SCENE_MANAGER_SCENE_COUNT_MAX 16
typedef struct {
scene_t *current;

View File

@@ -7,4 +7,5 @@
target_sources(${DUSK_TARGET_NAME}
PRIVATE
scriptmanager.c
scriptcontext.c
)

View File

@@ -0,0 +1,14 @@
/**
* 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 "assert/assert.h"
void scriptFuncCamera(scriptcontext_t *context) {
assertNotNull(context, "Script context cannot be NULL");
}

View File

@@ -0,0 +1,135 @@
/**
* 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 "rpg/entity/entity.h"
#include "assert/assert.h"
int32_t scriptFuncEntityAdd(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
assertTrue(lua_isinteger(L, 1), "Expected integer entity type");
lua_Integer entityType = luaL_checkinteger(L, 1);
assertTrue(
entityType >= ENTITY_TYPE_NULL && entityType < ENTITY_TYPE_COUNT,
"Invalid entity type passed to scriptFuncEntityAdd"
);
// Pop entity
uint8_t available = entityGetAvailable();
if(available == 0xFF) {
lua_pushnil(L);
return 1;
}
entity_t *ent = &ENTITIES[available];
entityInit(ent, (entitytype_t)entityType);
// May include X, Y and/or Z
if(lua_isinteger(L, 2)) {
lua_Integer xPos = luaL_checkinteger(L, 2);
ent->position.x = (int32_t)xPos;
}
if(lua_isinteger(L, 3)) {
lua_Integer yPos = luaL_checkinteger(L, 3);
ent->position.y = (int32_t)yPos;
}
if(lua_isinteger(L, 4)) {
lua_Integer zPos = luaL_checkinteger(L, 4);
ent->position.z = (int32_t)zPos;
}
// Send entity id.
lua_pushinteger(L, ent->id);
return 1;
}
int32_t scriptFuncEntitySetX(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
assertTrue(lua_isinteger(L, 1), "Expected integer entity id");
assertTrue(lua_isinteger(L, 2), "Expected integer x position");
lua_Integer entityId = luaL_checkinteger(L, 1);
lua_Integer xPos = luaL_checkinteger(L, 2);
assertTrue(
entityId >= 0 && entityId < ENTITY_COUNT,
"Invalid entity id passed to scriptFuncEntitySetX"
);
entity_t *ent = &ENTITIES[entityId];
assertTrue(
ent->type != ENTITY_TYPE_NULL,
"Cannot set position of NULL entity in scriptFuncEntitySetX"
);
ent->position.x = (int32_t)xPos;
return 0;
}
int32_t scriptFuncEntitySetY(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
assertTrue(lua_isinteger(L, 1), "Expected integer entity id");
assertTrue(lua_isinteger(L, 2), "Expected integer y position");
lua_Integer entityId = luaL_checkinteger(L, 1);
lua_Integer yPos = luaL_checkinteger(L, 2);
assertTrue(
entityId >= 0 && entityId < ENTITY_COUNT,
"Invalid entity id passed to scriptFuncEntitySetY"
);
entity_t *ent = &ENTITIES[entityId];
assertTrue(
ent->type != ENTITY_TYPE_NULL,
"Cannot set position of NULL entity in scriptFuncEntitySetY"
);
ent->position.y = (int32_t)yPos;
return 0;
}
int32_t scriptFuncEntitySetZ(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
assertTrue(lua_isinteger(L, 1), "Expected integer entity id");
assertTrue(lua_isinteger(L, 2), "Expected integer z position");
lua_Integer entityId = luaL_checkinteger(L, 1);
lua_Integer zPos = luaL_checkinteger(L, 2);
assertTrue(
entityId >= 0 && entityId < ENTITY_COUNT,
"Invalid entity id passed to scriptFuncEntitySetZ"
);
entity_t *ent = &ENTITIES[entityId];
assertTrue(
ent->type != ENTITY_TYPE_NULL,
"Cannot set position of NULL entity in scriptFuncEntitySetZ"
);
ent->position.z = (int32_t)zPos;
return 0;
}
void scriptFuncEntity(scriptcontext_t *context) {
assertNotNull(context, "Script context cannot be NULL");
scriptContextRegFunc(context, "entityAdd", scriptFuncEntityAdd);
scriptContextRegFunc(context, "entitySetX", scriptFuncEntitySetX);
scriptContextRegFunc(context, "entitySetY", scriptFuncEntitySetY);
scriptContextRegFunc(context, "entitySetZ", scriptFuncEntitySetZ);
}

View File

@@ -0,0 +1,39 @@
/**
* 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/scenemanager.h"
#include "debug/debug.h"
#include "assert/assert.h"
#include "error/error.h"
int32_t scriptFuncSetScene(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
assertTrue(lua_isstring(L, 1), "First argument must be a string");
const char_t *sceneName = lua_tostring(L, 1);
scene_t *scene = sceneManagerGetSceneByName(sceneName);
assertNotNull(scene, "Scene with given name does not exist");
sceneManagerSetScene(scene);
if(scene->init) {
errorret_t err = scene->init(&SCENE_MANAGER.sceneData);
assertTrue(err.code == ERROR_OK, "Scene initialization failed");
}
scene->flags |= SCENE_FLAG_INITIALIZED;
return 0;
}
void scriptFuncScene(scriptcontext_t *context) {
assertNotNull(context, "Script context cannot be NULL");
scriptContextRegFunc(context, "setScene", scriptFuncSetScene);
}

View File

@@ -0,0 +1,80 @@
/**
* 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 "debug/debug.h"
#include "assert/assert.h"
#include "util/string.h"
int32_t scriptFuncPrint(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
int n = lua_gettop(L);
luaL_Buffer b;
luaL_buffinit(L, &b);
for (int i = 1; i <= n; ++i) {
size_t len;
const char *s = luaL_tolstring(L, i, &len); // converts any value to string
luaL_addlstring(&b, s, len);
lua_pop(L, 1); // pop result of luaL_tolstring
if (i < n) luaL_addlstring(&b, "\t", 1);
}
luaL_pushresult(&b);
const char *msg = lua_tostring(L, -1);
debugPrint("%s\n", msg);
return 0; // no values returned to Lua
}
int32_t scriptFuncInclude(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
assertTrue(lua_isstring(L, 1), "Expected string filename");
scriptcontext_t* ctx = *(scriptcontext_t**)lua_getextraspace(L);
assertNotNull(ctx, "Script context cannot be NULL");
const char_t *filename = luaL_checkstring(L, 1);
assertNotNull(filename, "Filename cannot be NULL");
assertStrLenMin(filename, 1, "Filename cannot be empty");
// Copy out filename to mutable buffer
char_t buffer[1024];
stringCopy(buffer, filename, 1024);
// Ensure it has .dsf extension
size_t len = strlen(buffer);
if(len < 4 || strcmp(&buffer[len - 4], ".dsf") != 0) {
// Append .dsf
if(len + 4 >= 1024) {
luaL_error(L, "Filename too long to append .dsf");
return 0;
}
stringCopy(&buffer[len], ".dsf", 5);
}
// Execute the script file
errorret_t err = scriptContextExecFile(
ctx,
buffer
);
if(err.code != ERROR_OK) {
luaL_error(L, "Failed to include script file");
errorCatch(errorPrint(err));
return 0;
}
return 0;
}
void scriptFuncSystem(scriptcontext_t *context) {
assertNotNull(context, "Script context cannot be NULL");
scriptContextRegFunc(context, "print", scriptFuncPrint);
scriptContextRegFunc(context, "include", scriptFuncInclude);
}

196
src/script/scriptcontext.c Normal file
View File

@@ -0,0 +1,196 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "scriptcontext.h"
#include "assert/assert.h"
#include "asset/asset.h"
#include "util/memory.h"
#include "debug/debug.h"
#include "script/func/scriptfunccamera.h"
#include "script/func/scriptfuncentity.h"
#include "script/func/scriptfuncsystem.h"
#include "script/func/scriptfuncscene.h"
errorret_t scriptContextInit(scriptcontext_t *context) {
assertNotNull(context, "Script context cannot be NULL");
memoryZero(context, sizeof(scriptcontext_t));
// Create a new Lua state for this context.
context->luaState = luaL_newstate();
if(context->luaState == NULL) {
errorThrow("Failed to init Lua state");
}
luaL_openlibs(context->luaState);
// Store context in Lua extraspace
*(scriptcontext_t**)lua_getextraspace(context->luaState) = context;
// Register variables
// scriptContextExec(context, "PLATFORM = 'DESKTOP'");
// Register functions
scriptFuncSystem(context);
scriptFuncEntity(context);
scriptFuncCamera(context);
scriptFuncScene(context);
errorOk();
}
void scriptContextRegFunc(
scriptcontext_t *context,
const char_t *fnName,
lua_CFunction function
) {
assertNotNull(context, "Script context cannot be NULL");
assertNotNull(fnName, "Function name cannot be NULL");
assertNotNull(function, "Function cannot be NULL");
lua_register(context->luaState, fnName, function);
}
errorret_t scriptContextCallFunc(
scriptcontext_t *context,
const char_t *fnName,
const scriptvalue_t *args,
const int32_t argCount,
scriptvalue_t *retValue
) {
assertNotNull(context, "Script context cannot be NULL");
assertNotNull(fnName, "Function name cannot be NULL");
assertTrue(args == NULL || argCount >= 0, "Invalid arg count");
// Get func
lua_getglobal(context->luaState, fnName);
if(!lua_isfunction(context->luaState, -1)) {
errorThrow("Function '%s' not found in script context", fnName);
}
// Push args
for(int32_t i = 0; i < argCount; i++) {
const scriptvalue_t *arg = &args[i];
switch(arg->type) {
case SCRIPT_VALUE_TYPE_INT:
lua_pushinteger(context->luaState, arg->value.intValue);
break;
case SCRIPT_VALUE_TYPE_FLOAT:
lua_pushnumber(context->luaState, arg->value.floatValue);
break;
case SCRIPT_VALUE_TYPE_STRING:
lua_pushstring(context->luaState, arg->value.strValue);
break;
default:
errorThrow("Unsupported argument type %d", arg->type);
}
}
// Call func
if(lua_pcall(
context->luaState,
args ? argCount : 0,
retValue ? 1 : 0,
0
) != LUA_OK) {
const char_t *strErr = lua_tostring(context->luaState, -1);
lua_pop(context->luaState, 1);
errorThrow("Failed to call function '%s': %s", fnName, strErr);
}
// Was there a ret value?
if(retValue == NULL) {
errorOk();
}
// Get ret value
switch(retValue->type) {
case SCRIPT_VALUE_TYPE_INT:
if(!lua_isinteger(context->luaState, -1)) {
errorThrow("Expected integer return value from '%s'", fnName);
}
retValue->value.intValue = (int32_t)lua_tointeger(context->luaState, -1);
break;
case SCRIPT_VALUE_TYPE_FLOAT:
if(!lua_isnumber(context->luaState, -1)) {
errorThrow("Expected float return value from '%s'", fnName);
}
retValue->value.floatValue = (float)lua_tonumber(context->luaState, -1);
break;
case SCRIPT_VALUE_TYPE_BOOL:
if(!lua_isboolean(context->luaState, -1)) {
errorThrow("Expected boolean return value from '%s'", fnName);
}
retValue->value.boolValue = lua_toboolean(context->luaState, -1);
break;
// case SCRIPT_VALUE_TYPE_STRING:
// if(!lua_isstring(context->luaState, -1)) {
// errorThrow("Expected string return value from '%s'", fnName);
// }
// retValue->value.strValue = lua_tostring(context->luaState, -1);
// break;
default:
errorThrow("Unsupported return value type %d", retValue->type);
}
errorOk();
}
errorret_t scriptContextExec(scriptcontext_t *context, const char_t *script) {
assertNotNull(context, "Script context cannot be NULL");
assertNotNull(script, "Script cannot be NULL");
if(luaL_dostring(context->luaState, script) != LUA_OK) {
const char_t *strErr = lua_tostring(context->luaState, -1);
lua_pop(context->luaState, 1);
errorThrow("Failed to execute Lua: ", strErr);
}
errorOk();
}
errorret_t scriptContextExecFile(scriptcontext_t *ctx, const char_t *fname) {
assertNotNull(ctx, "Script context cannot be NULL");
assertNotNull(fname, "Filename cannot be NULL");
assetscript_t script;
errorChain(assetLoad(fname, &script));
if(lua_load(
ctx->luaState, assetScriptReader, &script, fname, NULL
) != LUA_OK) {
const char_t *strErr = lua_tostring(ctx->luaState, -1);
lua_pop(ctx->luaState, 1);
errorThrow("Failed to load Lua script: %s", strErr);
}
if(lua_pcall(ctx->luaState, 0, LUA_MULTRET, 0) != LUA_OK) {
const char_t *strErr = lua_tostring(ctx->luaState, -1);
lua_pop(ctx->luaState, 1);
errorThrow("Failed to execute Lua script: %s", strErr);
}
errorChain(assetScriptDispose(&script));
errorOk();
}
void scriptContextDispose(scriptcontext_t *context) {
assertNotNull(context, "Script context cannot be NULL");
assertNotNull(context->luaState, "Lua state is not initialized");
if(context->luaState != NULL) {
lua_close(context->luaState);
context->luaState = NULL;
}
}

View File

@@ -0,0 +1,82 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "error/error.h"
#include "scriptvalue.h"
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
typedef struct scriptcontext_s {
lua_State *luaState;
} scriptcontext_t;
/**
* Initialize a script context.
*
* @param context The script context to initialize.
* @return The error return value.
*/
errorret_t scriptContextInit(scriptcontext_t *context);
/**
* Register a C function within a script context.
*
* @param context The script context to use.
* @param fnName The name of the function in Lua.
* @param function The C function to register.
*/
void scriptContextRegFunc(
scriptcontext_t *context,
const char_t *fnName,
lua_CFunction function
);
/**
* Call a Lua function within a script context.
*
* @param context The script context to use.
* @param fnName The name of the Lua function to call.
* @param args Array of args to pass to the function (or NULL for no args)
* @param argCount The number of arguments in the args array (omitable).
* @param retValue Output to store returned value (or NULL for no return value).
* @return The error return value.
*/
errorret_t scriptContextCallFunc(
scriptcontext_t *context,
const char_t *fnName,
const scriptvalue_t *args,
const int32_t argCount,
scriptvalue_t *retValue
);
/**
* Execute a script within a script context.
*
* @param context The script context to use.
* @param script The script to execute.
* @return The error return value.
*/
errorret_t scriptContextExec(scriptcontext_t *context, const char_t *script);
/**
* Execute a script from a file within a script context.
*
* @param ctx The script context to use.
* @param fname The filename of the script to execute.
* @return The error return value.
*/
errorret_t scriptContextExecFile(scriptcontext_t *ctx, const char_t *fname);
/**
* Dispose of a script context.
*
* @param context The script context to dispose of.
*/
void scriptContextDispose(scriptcontext_t *context);

View File

@@ -8,74 +8,16 @@
#include "scriptmanager.h"
#include "util/memory.h"
#include "assert/assert.h"
#include "debug/debug.h"
#include "asset/asset.h"
int luaCallable(lua_State *L) {
printf("This function was called from Lua!\n");
return 0;
}
scriptmanager_t SCRIPT_MANAGER;
errorret_t scriptManagerInit() {
memoryZero(&SCRIPT_MANAGER, sizeof(scriptmanager_t));
SCRIPT_MANAGER.luaState = luaL_newstate();
if(SCRIPT_MANAGER.luaState == NULL) {
errorThrow("Failed to init Lua state");
}
luaL_openlibs(SCRIPT_MANAGER.luaState);
lua_register(SCRIPT_MANAGER.luaState, "luaCallable", luaCallable);
errorChain(scriptManagerExecFile("script/test.dsf"));
errorOk();
}
errorret_t scriptManagerExecString(const char_t *script) {
assertNotNull(script, "Script cannot be NULL");
assertNotNull(SCRIPT_MANAGER.luaState, "Lua state is not initialized");
if(luaL_dostring(SCRIPT_MANAGER.luaState, script) != LUA_OK) {
const char_t *strErr = lua_tostring(SCRIPT_MANAGER.luaState, -1);
lua_pop(SCRIPT_MANAGER.luaState, 1);
errorThrow("Failed to execute Lua: ", strErr);
}
errorOk();
}
errorret_t scriptManagerExecFile(const char_t *filename) {
assertNotNull(filename, "Filename cannot be NULL");
assertNotNull(SCRIPT_MANAGER.luaState, "Lua state is not initialized");
assetscript_t script;
errorChain(assetLoad(filename, &script));
if(lua_load(
SCRIPT_MANAGER.luaState, assetScriptReader, &script, filename, NULL
) != LUA_OK) {
const char_t *strErr = lua_tostring(SCRIPT_MANAGER.luaState, -1);
lua_pop(SCRIPT_MANAGER.luaState, 1);
errorThrow("Failed to load Lua script: %s", strErr);
}
if(lua_pcall(SCRIPT_MANAGER.luaState, 0, LUA_MULTRET, 0) != LUA_OK) {
const char_t *strErr = lua_tostring(SCRIPT_MANAGER.luaState, -1);
lua_pop(SCRIPT_MANAGER.luaState, 1);
errorThrow("Failed to execute Lua script: %s", strErr);
}
errorChain(assetScriptDispose(&script));
errorOk();
}
errorret_t scriptManagerDispose() {
if(SCRIPT_MANAGER.luaState != NULL) {
lua_close(SCRIPT_MANAGER.luaState);
SCRIPT_MANAGER.luaState = NULL;
}
errorOk();
}

View File

@@ -7,12 +7,10 @@
#pragma once
#include "error/error.h"
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include "scriptcontext.h"
typedef struct scriptmanager_s {
lua_State *luaState;
scriptcontext_t mainContext;
} scriptmanager_t;
extern scriptmanager_t SCRIPT_MANAGER;
@@ -24,22 +22,6 @@ extern scriptmanager_t SCRIPT_MANAGER;
*/
errorret_t scriptManagerInit();
/**
* Execute a Lua script.
*
* @param script The script to execute.
* @return The error return value.
*/
errorret_t scriptManagerExecString(const char_t *script);
/**
* Execute a Lua script from a file.
*
* @param filename The filename of the script to execute.
* @return The error return value.
*/
errorret_t scriptManagerExecFile(const char_t *filename);
/**
* Dispose of the script manager.
*

26
src/script/scriptvalue.h Normal file
View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
#define SCRIPT_VALUE_TYPE_NIL 0
#define SCRIPT_VALUE_TYPE_INT 1
#define SCRIPT_VALUE_TYPE_FLOAT 2
#define SCRIPT_VALUE_TYPE_STRING 3
#define SCRIPT_VALUE_TYPE_BOOL 4
typedef struct scriptvalue_s {
uint8_t type;
union {
int32_t intValue;
float floatValue;
const char_t *strValue;
bool boolValue;
} value;
} scriptvalue_t;

View File

@@ -12,3 +12,6 @@ target_sources(${DUSK_TARGET_NAME}
uiframe.c
uitextbox.c
)
# Subdirs
add_subdirectory(element)

View File

@@ -0,0 +1,9 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_TARGET_NAME}
PRIVATE
)

View File

@@ -6,8 +6,11 @@
*/
#pragma once
#include "dusk.h"
typedef struct cutscene_s cutscene_t;
typedef enum {
UI_ELEMENT_TYPE_NULL,
typedef cutscene_t* cutscenecutscene_t;
UI_ELEMENT_TYPE_TEXT,
UI_ELEMENT_TYPE_COUNT,
} uielementtype_t;

View File

@@ -3,7 +3,7 @@ import os
from assetstool.args import args
from assetstool.assetcache import assetCache, assetGetCache
from assetstool.assethelpers import getAssetRelativePath
from dusk.defs import defs
from dusk.defs import fileDefs
def processScript(asset):
cache = assetGetCache(asset['path'])
@@ -16,6 +16,10 @@ def processScript(asset):
# TODO: I will precompile or minify the Lua code here in the future
# Replace all definitions in the code
for key, val in fileDefs.items():
luaCode = luaCode.replace(key, str(val))
# Create output Dusk Script File (DSF) data
data = ""
data += "DSF"

View File

@@ -1,4 +1,4 @@
from dotenv import load_dotenv
from dotenv import load_dotenv, dotenv_values
import os
import sys
@@ -13,6 +13,8 @@ if not os.path.isfile(duskDefsPath):
load_dotenv(dotenv_path=duskDefsPath)
defs = {key: os.getenv(key) for key in os.environ.keys()}
fileDefs = dotenv_values(dotenv_path=duskDefsPath)
# Parsed out definitions
CHUNK_WIDTH = int(defs.get('CHUNK_WIDTH'))
CHUNK_HEIGHT = int(defs.get('CHUNK_HEIGHT'))