Lua script something
Some checks failed
Build Dusk / build-linux (push) Failing after 2m56s
Build Dusk / build-psp (push) Failing after 1m49s

This commit is contained in:
2025-12-04 00:02:26 -06:00
parent 9aaf271996
commit 9f507be7bc
16 changed files with 369 additions and 1 deletions

View File

@@ -12,5 +12,6 @@ add_subdirectory(palette)
add_subdirectory(locale) add_subdirectory(locale)
add_subdirectory(entity) add_subdirectory(entity)
add_subdirectory(script)
add_subdirectory(map) add_subdirectory(map)
add_subdirectory(ui) add_subdirectory(ui)

View File

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

1
assets/script/test.lua Normal file
View File

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

View File

@@ -0,0 +1,59 @@
# 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,6 +5,7 @@
find_package(cglm REQUIRED) find_package(cglm REQUIRED)
find_package(libzip REQUIRED) find_package(libzip REQUIRED)
find_package(lua REQUIRED)
# Libs # Libs
target_link_libraries(${DUSK_TARGET_NAME} target_link_libraries(${DUSK_TARGET_NAME}
@@ -12,6 +13,7 @@ target_link_libraries(${DUSK_TARGET_NAME}
m m
cglm cglm
zip zip
lua
pthread pthread
) )
@@ -41,6 +43,7 @@ add_subdirectory(input)
add_subdirectory(locale) add_subdirectory(locale)
add_subdirectory(rpg) add_subdirectory(rpg)
add_subdirectory(scene) add_subdirectory(scene)
add_subdirectory(script)
add_subdirectory(thread) add_subdirectory(thread)
add_subdirectory(time) add_subdirectory(time)
add_subdirectory(ui) add_subdirectory(ui)

View File

@@ -11,6 +11,7 @@
#include "type/assetlanguage.h" #include "type/assetlanguage.h"
#include "type/assetmap.h" #include "type/assetmap.h"
#include "type/assetchunk.h" #include "type/assetchunk.h"
#include "type/assetscript.h"
#include <zip.h> #include <zip.h>
typedef enum { typedef enum {
@@ -21,6 +22,7 @@ typedef enum {
ASSET_TYPE_LANGUAGE, ASSET_TYPE_LANGUAGE,
ASSET_TYPE_MAP, ASSET_TYPE_MAP,
ASSET_TYPE_CHUNK, ASSET_TYPE_CHUNK,
ASSET_TYPE_SCRIPT,
ASSET_TYPE_COUNT, ASSET_TYPE_COUNT,
} assettype_t; } assettype_t;
@@ -81,5 +83,11 @@ static const assettypedef_t ASSET_TYPE_DEFINITIONS[ASSET_TYPE_COUNT] = {
.header = "DCF", .header = "DCF",
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM, .loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
.custom = assetChunkLoad .custom = assetChunkLoad
},
[ASSET_TYPE_SCRIPT] = {
.header = "DSF",
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
.custom = assetScriptHandler
} }
}; };

View File

@@ -11,4 +11,5 @@ target_sources(${DUSK_TARGET_NAME}
assetlanguage.c assetlanguage.c
assetmap.c assetmap.c
assetchunk.c assetchunk.c
assetscript.c
) )

View File

@@ -0,0 +1,58 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "asset/asset.h"
#include "assert/assert.h"
errorret_t assetScriptHandler(assetcustom_t custom) {
assertNotNull(custom.zipFile, "Custom asset zip file cannot be NULL");
assertNotNull(custom.output, "Custom asset output cannot be NULL");
assetscript_t *script = (assetscript_t *)custom.output;
errorChain(assetScriptInit(script, custom.zipFile));
errorOk();
}
errorret_t assetScriptInit(
assetscript_t *script,
zip_file_t *zipFile
) {
assertNotNull(script, "Script asset cannot be NULL");
assertNotNull(zipFile, "Zip file cannot be NULL");
// We now own the zip file handle.
script->zip = zipFile;
errorOk();
}
const char_t * assetScriptReader(lua_State* lState, void* data, size_t* size) {
assetscript_t *script = (assetscript_t *)data;
zip_int64_t bytesRead = zip_fread(
script->zip, script->buffer, sizeof(script->buffer)
);
if(bytesRead < 0) {
*size = 0;
return NULL;
}
*size = (size_t)bytesRead;
return script->buffer;
}
errorret_t assetScriptDispose(assetscript_t *script) {
assertNotNull(script, "Script asset cannot be NULL");
if(script->zip != NULL) {
zip_fclose(script->zip);
script->zip = NULL;
}
errorOk();
}

View File

@@ -0,0 +1,57 @@
/**
* 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 "duskdefs.h"
#include <zip.h>
#include <lua.h>
#define ASSET_SCRIPT_BUFFER_SIZE 1024
typedef struct assetscript_s {
zip_file_t *zip;
char_t buffer[ASSET_SCRIPT_BUFFER_SIZE];
} assetscript_t;
typedef struct assetcustom_s assetcustom_t;
/**
* Receiving function from the asset manager to handle script assets.
*
* @param custom Custom asset loading data.
* @return Error code.
*/
errorret_t assetScriptHandler(assetcustom_t custom);
/**
* Initializes a script asset.
*
* @param script Script asset to initialize.
* @param zipFile Zip file handle for the script asset.
* @return Error code.
*/
errorret_t assetScriptInit(assetscript_t *script, zip_file_t *zipFile);
/**
* Reader function for Lua to read script data from the asset.
*
* @param L Lua state.
* @param data Pointer to the assetscript_t structure.
* @param size Pointer to store the size of the read data.
* @return Pointer to the read data buffer.
*/
const char_t * assetScriptReader(lua_State* L, void* data, size_t* size);
/**
* Disposes of a script asset, freeing any allocated resources.
*
* @param script Script asset to dispose of.
* @return Error code.
*/
errorret_t assetScriptDispose(assetscript_t *script);

View File

@@ -15,6 +15,7 @@
#include "asset/asset.h" #include "asset/asset.h"
#include "ui/ui.h" #include "ui/ui.h"
#include "rpg/rpg.h" #include "rpg/rpg.h"
#include "script/scriptmanager.h"
#include "debug/debug.h" #include "debug/debug.h"
engine_t ENGINE; engine_t ENGINE;
@@ -35,6 +36,12 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
errorChain(uiInit()); errorChain(uiInit());
errorChain(rpgInit()); errorChain(rpgInit());
errorChain(sceneManagerInit()); errorChain(sceneManagerInit());
errorChain(scriptManagerInit());
// scriptManagerExec(
// "print('Hello from Lua!')\n"
// "luaCallable()\n"
// );
errorOk(); errorOk();
} }

View File

@@ -11,6 +11,7 @@
#include "input/input.h" #include "input/input.h"
int main(int argc, char **argv) { int main(int argc, char **argv) {
// Main applet
errorret_t ret; errorret_t ret;
// Init engine // Init engine

10
src/script/CMakeLists.txt Normal file
View File

@@ -0,0 +1,10 @@
# 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
scriptmanager.c
)

View File

@@ -0,0 +1,74 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "scriptmanager.h"
#include "util/memory.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);
// SCript test
assetscript_t script;
assetLoad("script/test.dsf", &script);
if(lua_load(SCRIPT_MANAGER.luaState, assetScriptReader, &script, "script/test.dsf", 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);
}
assetScriptDispose(&script);
errorOk();
}
errorret_t scriptManagerExec(const char_t *script) {
if(SCRIPT_MANAGER.luaState == NULL) {
errorThrow("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 scriptManagerDispose() {
if(SCRIPT_MANAGER.luaState != NULL) {
lua_close(SCRIPT_MANAGER.luaState);
SCRIPT_MANAGER.luaState = NULL;
}
errorOk();
}

View File

@@ -0,0 +1,40 @@
/**
* 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 <lua.h>
#include <lauxlib.h>
#include <lualib.h>
typedef struct scriptmanager_s {
lua_State *luaState;
} scriptmanager_t;
extern scriptmanager_t SCRIPT_MANAGER;
/**
* Initialize the script manager.
*
* @return The error return value.
*/
errorret_t scriptManagerInit();
/**
* Execute a Lua script.
*
* @param script The script to execute.
* @return The error return value.
*/
errorret_t scriptManagerExec(const char_t *script);
/**
* Dispose of the script manager.
*
* @return The error return value.
*/
errorret_t scriptManagerDispose();

View File

@@ -5,6 +5,7 @@ from assetstool.processpalette import processPalette
from assetstool.processtileset import processTileset from assetstool.processtileset import processTileset
from assetstool.processmap import processMap from assetstool.processmap import processMap
from assetstool.processlanguage import processLanguage from assetstool.processlanguage import processLanguage
from assetstool.processscript import processScript
processedAssets = [] processedAssets = []
@@ -25,6 +26,8 @@ def processAsset(asset):
return processMap(asset) return processMap(asset)
elif t == 'language': elif t == 'language':
return processLanguage(asset) return processLanguage(asset)
elif t == 'script':
return processScript(asset)
else: else:
print(f"Error: Unknown asset type '{asset['type']}' for path '{asset['path']}'") print(f"Error: Unknown asset type '{asset['type']}' for path '{asset['path']}'")
sys.exit(1) sys.exit(1)

View File

@@ -0,0 +1,39 @@
import sys
import os
from assetstool.args import args
from assetstool.assetcache import assetCache, assetGetCache
from assetstool.assethelpers import getAssetRelativePath
from dusk.defs import defs
def processScript(asset):
cache = assetGetCache(asset['path'])
if cache is not None:
return cache
# Load the lua file as a string
with open(asset['path'], 'r', encoding='utf-8') as f:
luaCode = f.read()
# TODO: I will precompile or minify the Lua code here in the future
# Create output Dusk Script File (DSF) data
data = ""
data += "DSF"
data += luaCode
# Write to relative output file path.
relative = getAssetRelativePath(asset['path'])
fileNameWithoutExt = os.path.splitext(os.path.basename(asset['path']))[0]
outputFileRelative = os.path.join(os.path.dirname(relative), f"{fileNameWithoutExt}.dsf")
outputFilePath = os.path.join(args.output_assets, outputFileRelative)
os.makedirs(os.path.dirname(outputFilePath), exist_ok=True)
with open(outputFilePath, "wb") as f:
f.write(data.encode('utf-8'))
outScript = {
'data': data,
'path': asset['path'],
'files': [ outputFilePath ],
'scriptPath': outputFileRelative,
}
return assetCache(asset['path'], outScript)