Add script context
This commit is contained in:
@@ -11,7 +11,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/mod
|
||||
|
||||
if(NOT DEFINED DUSK_TARGET_SYSTEM)
|
||||
set(DUSK_TARGET_SYSTEM "linux")
|
||||
#set(DUSK_TARGET_SYSTEM "psp")
|
||||
# set(DUSK_TARGET_SYSTEM "psp")
|
||||
endif()
|
||||
|
||||
# Prep cache
|
||||
|
||||
@@ -1 +1,7 @@
|
||||
print("Test Lua script")
|
||||
function testFunction()
|
||||
print("Hello from testFunction!")
|
||||
end
|
||||
|
||||
function doAdd(a, b)
|
||||
return a + b
|
||||
end
|
||||
@@ -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");
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "script/scriptmanager.h"
|
||||
#include "debug/debug.h"
|
||||
|
||||
#include "script/scriptcontext.h"
|
||||
|
||||
engine_t ENGINE;
|
||||
|
||||
errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
@@ -38,10 +40,20 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
errorChain(sceneManagerInit());
|
||||
errorChain(scriptManagerInit());
|
||||
|
||||
// scriptManagerExec(
|
||||
// "print('Hello from Lua!')\n"
|
||||
// "luaCallable()\n"
|
||||
// );
|
||||
scriptcontext_t testCtx;
|
||||
errorChain(scriptContextInit(&testCtx));
|
||||
errorChain(scriptContextExecFile(&testCtx, "script/test.dsf"));
|
||||
errorChain(scriptContextCallFunc(&testCtx, "testFunction", NULL, 0, NULL));
|
||||
|
||||
scriptvalue_t args[2] = {
|
||||
{ .type = SCRIPT_VALUE_TYPE_INT, .value.intValue = 5 },
|
||||
{ .type = SCRIPT_VALUE_TYPE_INT, .value.intValue = 7 }
|
||||
};
|
||||
scriptvalue_t ret = { .type = SCRIPT_VALUE_TYPE_INT };
|
||||
errorChain(scriptContextCallFunc(&testCtx, "doAdd", args, 2, &ret));
|
||||
printf("doAdd returned: %d\n", ret.value.intValue);
|
||||
|
||||
scriptContextDispose(&testCtx);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -55,7 +67,6 @@ errorret_t engineUpdate(void) {
|
||||
sceneManagerUpdate();
|
||||
errorChain(displayUpdate());
|
||||
|
||||
|
||||
if(inputPressed(INPUT_ACTION_RAGEQUIT)) ENGINE.running = false;
|
||||
|
||||
errorOk();
|
||||
|
||||
@@ -7,4 +7,5 @@
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
scriptmanager.c
|
||||
scriptcontext.c
|
||||
)
|
||||
196
src/script/scriptcontext.c
Normal file
196
src/script/scriptcontext.c
Normal 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"
|
||||
|
||||
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);
|
||||
|
||||
// Register shared functions
|
||||
scriptContextRegFunc(context, "print", scriptContextPrint);
|
||||
|
||||
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_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();
|
||||
}
|
||||
|
||||
int32_t scriptContextPrint(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
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
90
src/script/scriptcontext.h
Normal file
90
src/script/scriptcontext.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Overridden print function for Lua scripts to output to debug.
|
||||
*
|
||||
* @param L The Lua state.
|
||||
* @return The number of return values.
|
||||
*/
|
||||
int32_t scriptContextPrint(lua_State *L);
|
||||
|
||||
/**
|
||||
* Dispose of a script context.
|
||||
*
|
||||
* @param context The script context to dispose of.
|
||||
*/
|
||||
void scriptContextDispose(scriptcontext_t *context);
|
||||
@@ -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();
|
||||
}
|
||||
@@ -7,12 +7,9 @@
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
|
||||
typedef struct scriptmanager_s {
|
||||
lua_State *luaState;
|
||||
void *nothing;
|
||||
} scriptmanager_t;
|
||||
|
||||
extern scriptmanager_t SCRIPT_MANAGER;
|
||||
@@ -24,22 +21,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
26
src/script/scriptvalue.h
Normal 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;
|
||||
@@ -12,3 +12,6 @@ target_sources(${DUSK_TARGET_NAME}
|
||||
uiframe.c
|
||||
uitextbox.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(element)
|
||||
9
src/ui/element/CMakeLists.txt
Normal file
9
src/ui/element/CMakeLists.txt
Normal 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
|
||||
)
|
||||
16
src/ui/element/uielementtype.h
Normal file
16
src/ui/element/uielementtype.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
UI_ELEMENT_TYPE_NULL,
|
||||
|
||||
UI_ELEMENT_TYPE_TEXT,
|
||||
|
||||
UI_ELEMENT_TYPE_COUNT,
|
||||
} uielementtype_t;
|
||||
Reference in New Issue
Block a user