Files
dusk/src/script/scriptcontext.cpp
Dominic Masters 5b95669482
Some checks failed
Build Dusk / build-linux (push) Failing after 1m11s
Build Dusk / build-psp (push) Failing after 1m20s
Assert.hpp
2025-12-23 20:21:05 +10:00

205 lines
5.6 KiB
C++

/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "scriptcontext.hpp"
#include "assert/Assert.hpp"
#include "asset/asset.hpp"
#include "util/memory.hpp"
#include "debug/debug.hpp"
#include "script/func/scriptfunccamera.hpp"
#include "script/func/scriptfuncentity.hpp"
#include "script/func/scriptfuncsystem.hpp"
void 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) {
throw std::runtime_error("Failed to init Lua state");
}
luaL_openlibs(context->luaState);
// Register functions
scriptFuncSystem(context);
scriptFuncEntity(context);
}
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);
}
void 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)) {
throw std::runtime_error(
"Function '" + std::string(fnName) + "' not found in script context"
);
}
// 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:
throw std::runtime_error(
"Unsupported argument type " + std::to_string(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);
throw std::runtime_error(
"Failed to call Lua function '" +
std::string(fnName) +
"': " +
std::string(strErr)
);
}
// Was there a ret value?
if(retValue == NULL) return;
// Get ret value
switch(retValue->type) {
case SCRIPT_VALUE_TYPE_INT:
if(!lua_isinteger(context->luaState, -1)) {
throw std::runtime_error(
"Expected integer return value from '" +
std::string(fnName) +
"'"
);
}
retValue->value.intValue = (int32_t)lua_tointeger(context->luaState, -1);
break;
case SCRIPT_VALUE_TYPE_FLOAT:
if(!lua_isnumber(context->luaState, -1)) {
throw std::runtime_error(
"Expected float return value from '" +
std::string(fnName) +
"'"
);
}
retValue->value.floatValue = (float)lua_tonumber(context->luaState, -1);
break;
case SCRIPT_VALUE_TYPE_BOOL:
if(!lua_isboolean(context->luaState, -1)) {
throw std::runtime_error(
"Expected boolean return value from '" +
std::string(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:
throw std::runtime_error(
"Unsupported return value type " + std::to_string(retValue->type)
);
}
}
void 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);
throw std::runtime_error("Failed to execute Lua: " + std::string(strErr));
}
}
void scriptContextExecFile(scriptcontext_t *ctx, const char_t *fname) {
assertNotNull(ctx, "Script context cannot be NULL");
assertNotNull(fname, "Filename cannot be NULL");
assetscript_t script;
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);
throw std::runtime_error(
"Failed to load Lua script: " + std::string(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);
throw std::runtime_error(
"Failed to execute Lua script: " + std::string(strErr)
);
}
assetScriptDispose(&script);
}
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;
}
}