Compare commits
5 Commits
77d3c54ebb
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f39b2060a8 | |||
| aed202ebf9 | |||
| a495179e5f | |||
| 4e1b404820 | |||
| 8c74ee31e0 |
@@ -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
|
||||
|
||||
@@ -4,3 +4,5 @@
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_asset(SCRIPT test.lua)
|
||||
|
||||
add_subdirectory(scene)
|
||||
5
assets/script/init.lua
Normal file
5
assets/script/init.lua
Normal file
@@ -0,0 +1,5 @@
|
||||
print('Init')
|
||||
|
||||
-- Load map scene
|
||||
setScene('map')
|
||||
setMap()
|
||||
4
assets/script/scene/CMakeLists.txt
Normal file
4
assets/script/scene/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
@@ -1 +0,0 @@
|
||||
print("Test Lua script")
|
||||
@@ -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()
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -7,4 +7,5 @@
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
scriptmanager.c
|
||||
scriptcontext.c
|
||||
)
|
||||
14
src/script/func/scriptfunccamera.h
Normal file
14
src/script/func/scriptfunccamera.h
Normal 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");
|
||||
}
|
||||
135
src/script/func/scriptfuncentity.h
Normal file
135
src/script/func/scriptfuncentity.h
Normal 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);
|
||||
}
|
||||
39
src/script/func/scriptfuncscene.h
Normal file
39
src/script/func/scriptfuncscene.h
Normal 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);
|
||||
}
|
||||
80
src/script/func/scriptfuncsystem.h
Normal file
80
src/script/func/scriptfuncsystem.h
Normal 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
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"
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
82
src/script/scriptcontext.h
Normal file
82
src/script/scriptcontext.h
Normal 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);
|
||||
@@ -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,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
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
|
||||
)
|
||||
@@ -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;
|
||||
@@ -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"
|
||||
|
||||
@@ -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'))
|
||||
|
||||
Reference in New Issue
Block a user