Compare commits

..

7 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
77d3c54ebb Fixed PSP build
Some checks failed
Build Dusk / build-linux (push) Failing after 1m53s
Build Dusk / build-psp (push) Failing after 1m27s
2025-12-04 00:33:42 -06:00
b5de39926b Lua 2025-12-04 00:30:44 -06:00
34 changed files with 658 additions and 186 deletions

View File

@@ -17,7 +17,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
apt-get update apt-get update
apt-get install -y build-essential cmake python3 python3-pip python3-polib python3-pil libsdl2-dev libgl1-mesa-dev libzip-dev python3-dotenv python3-pyqt5 python3-opengl apt-get install -y build-essential cmake python3 python3-pip python3-polib python3-pil libsdl2-dev libgl1-mesa-dev libzip-dev python3-dotenv python3-pyqt5 python3-opengl liblua5.3-dev
- name: Configure CMake - name: Configure CMake
run: cmake -S . -B build -DDUSK_TARGET_SYSTEM=linux run: cmake -S . -B build -DDUSK_TARGET_SYSTEM=linux
- name: Build - name: Build
@@ -39,7 +39,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
apt-get update apt-get update
apt-get install -y build-essential cmake python3 python3-pip python3-polib python3-pil libsdl2-dev libgl1-mesa-dev libzip-dev python3-dotenv python3-pyqt5 python3-opengl apt-get install -y build-essential cmake python3 python3-pip python3-polib python3-pil libsdl2-dev libgl1-mesa-dev libzip-dev python3-dotenv python3-pyqt5 python3-opengl liblua5.3-dev
- name: Configure CMake - name: Configure CMake
run: cmake -S . -B build -DDUSK_TARGET_SYSTEM=psp run: cmake -S . -B build -DDUSK_TARGET_SYSTEM=psp
- name: Build - name: Build

View File

@@ -11,7 +11,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/mod
if(NOT DEFINED DUSK_TARGET_SYSTEM) if(NOT DEFINED DUSK_TARGET_SYSTEM)
set(DUSK_TARGET_SYSTEM "linux") set(DUSK_TARGET_SYSTEM "linux")
#set(DUSK_TARGET_SYSTEM "psp") # set(DUSK_TARGET_SYSTEM "psp")
endif() endif()
# Prep cache # Prep cache

View File

@@ -4,3 +4,5 @@
# https://opensource.org/licenses/MIT # https://opensource.org/licenses/MIT
add_asset(SCRIPT test.lua) 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(cglm REQUIRED)
find_package(libzip 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 # Libs
target_link_libraries(${DUSK_TARGET_NAME} target_link_libraries(${DUSK_TARGET_NAME}
@@ -13,8 +23,8 @@ target_link_libraries(${DUSK_TARGET_NAME}
m m
cglm cglm
zip zip
lua
pthread pthread
Lua::Lua
) )
# Includes # Includes

View File

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

View File

@@ -291,12 +291,12 @@ void screenRender() {
return; return;
} }
#if DISPLAY_SIZE_DYNAMIC == 1
if(SCREEN.mode == SCREEN_MODE_FIXED_VIEWPORT_HEIGHT) { if(SCREEN.mode == SCREEN_MODE_FIXED_VIEWPORT_HEIGHT) {
glViewport(0, 0, SCREEN.width, SCREEN.height); glViewport(0, 0, SCREEN.width, SCREEN.height);
return; return;
} }
#if DISPLAY_SIZE_DYNAMIC == 1
if( if(
SCREEN.mode == SCREEN_MODE_ASPECT_RATIO || SCREEN.mode == SCREEN_MODE_ASPECT_RATIO ||
SCREEN.mode == SCREEN_MODE_FIXED_HEIGHT || SCREEN.mode == SCREEN_MODE_FIXED_HEIGHT ||

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,4 +7,5 @@
target_sources(${DUSK_TARGET_NAME} target_sources(${DUSK_TARGET_NAME}
PRIVATE PRIVATE
scriptmanager.c 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 "scriptmanager.h"
#include "util/memory.h" #include "util/memory.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "debug/debug.h"
#include "asset/asset.h" #include "asset/asset.h"
int luaCallable(lua_State *L) {
printf("This function was called from Lua!\n");
return 0;
}
scriptmanager_t SCRIPT_MANAGER; scriptmanager_t SCRIPT_MANAGER;
errorret_t scriptManagerInit() { errorret_t scriptManagerInit() {
memoryZero(&SCRIPT_MANAGER, sizeof(scriptmanager_t)); 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(); errorOk();
} }
errorret_t scriptManagerDispose() { errorret_t scriptManagerDispose() {
if(SCRIPT_MANAGER.luaState != NULL) {
lua_close(SCRIPT_MANAGER.luaState);
SCRIPT_MANAGER.luaState = NULL;
}
errorOk(); errorOk();
} }

View File

@@ -7,12 +7,10 @@
#pragma once #pragma once
#include "error/error.h" #include "error/error.h"
#include <lua.h> #include "scriptcontext.h"
#include <lauxlib.h>
#include <lualib.h>
typedef struct scriptmanager_s { typedef struct scriptmanager_s {
lua_State *luaState; scriptcontext_t mainContext;
} scriptmanager_t; } scriptmanager_t;
extern scriptmanager_t SCRIPT_MANAGER; extern scriptmanager_t SCRIPT_MANAGER;
@@ -24,22 +22,6 @@ extern scriptmanager_t SCRIPT_MANAGER;
*/ */
errorret_t scriptManagerInit(); 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. * 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 uiframe.c
uitextbox.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 #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.args import args
from assetstool.assetcache import assetCache, assetGetCache from assetstool.assetcache import assetCache, assetGetCache
from assetstool.assethelpers import getAssetRelativePath from assetstool.assethelpers import getAssetRelativePath
from dusk.defs import defs from dusk.defs import fileDefs
def processScript(asset): def processScript(asset):
cache = assetGetCache(asset['path']) cache = assetGetCache(asset['path'])
@@ -16,6 +16,10 @@ def processScript(asset):
# TODO: I will precompile or minify the Lua code here in the future # 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 # Create output Dusk Script File (DSF) data
data = "" data = ""
data += "DSF" data += "DSF"

View File

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