mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-08 07:28:22 -10:00
This commit changes the way the scripting API works by properly using the newly available type information for moving the FSO resources into the memory supplied by lua. This has full support for rvalue references which will make it possible to use move-only types with the scripting API. This also makes the API much safer to use since it doesn't use pointers to local values anymore which made it very hard to use the API in a different context without causing issues. This only covers writing the FSO values to Lua. Getting values back is not covered yet.
143 lines
4.7 KiB
C++
143 lines
4.7 KiB
C++
|
|
#include "scripting/ade_args.h"
|
|
#include "scripting/ade.h"
|
|
|
|
#include "scripting/lua/LuaTable.h"
|
|
#include "scripting/lua/LuaFunction.h"
|
|
#include "scripting/lua/LuaConvert.h"
|
|
|
|
#include "mod_table/mod_table.h"
|
|
|
|
#include <utf8.h>
|
|
|
|
namespace scripting {
|
|
|
|
namespace internal {
|
|
|
|
// WMC - hack to skip X number of arguments on the stack
|
|
// Lets me use ade_get_args for global hook return values
|
|
int Ade_get_args_skip = 0;
|
|
bool Ade_get_args_lfunction = false;
|
|
|
|
bool get_single_arg(lua_State* L, const get_args_state& state, char fmt, bool* b)
|
|
{
|
|
Assertion(fmt == 'b', "Invalid character '%c' for boolean type!", fmt);
|
|
|
|
if (lua_isboolean(L, state.nargs)) {
|
|
*b = lua_toboolean(L, state.nargs) > 0;
|
|
} else {
|
|
LuaError(L, "%s: Argument %d is an invalid type '%s'; boolean expected", state.funcname, state.nargs,
|
|
ade_get_type_string(L, state.nargs));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool get_single_arg(lua_State* L, const get_args_state& state, char fmt, const char** s)
|
|
{
|
|
Assertion(fmt == 's', "Invalid character '%c' for string type!", fmt);
|
|
|
|
if (lua_isstring(L, state.nargs)) {
|
|
auto value = lua_tostring(L, state.nargs);
|
|
|
|
if (Unicode_text_mode) {
|
|
// Validate the string when we are in unicode mode to ensure that FSO doesn't just crash when a
|
|
// script passes an invalid UTF-8 sequence to the API
|
|
auto end = value + strlen(value);
|
|
auto invalid = utf8::find_invalid(value, end);
|
|
|
|
if (invalid != end) {
|
|
if (invalid == value) {
|
|
// The first character is the invalid sequence
|
|
LuaError(L, "An invalid UTF-8 encoding sequence was detected! The first invalid character "
|
|
"was as the start of the string.");
|
|
} else {
|
|
// If the invalid sequence is inside the string then we try to give some context to make
|
|
// finding the bug easier
|
|
auto display_text_start = std::max(value, invalid - 32);
|
|
SCP_string context_text(display_text_start, invalid);
|
|
|
|
LuaError(L,
|
|
"An invalid UTF-8 encoding sequence was detected! The error was detected directly "
|
|
"after this string \"%s\".",
|
|
context_text.c_str());
|
|
}
|
|
|
|
// Finally, assign a default value so that we can continue
|
|
value = "Invalid UTF-8 sequence detected!";
|
|
}
|
|
}
|
|
|
|
*s = value;
|
|
} else {
|
|
LuaError(L, "%s: Argument %d is an invalid type '%s'; string expected", state.funcname, state.nargs,
|
|
ade_get_type_string(L, state.nargs));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool get_single_arg(lua_State* L, const get_args_state& state, char fmt, ade_odata od)
|
|
{
|
|
Assertion(fmt == 'o', "Invalid character '%c' for object type!", fmt);
|
|
|
|
if (lua_isuserdata(L, state.nargs)) {
|
|
// Use the helper function
|
|
if (!luacpp::convert::popValue(L, od, state.nargs, false)) {
|
|
return false;
|
|
}
|
|
} else if (lua_isnil(L, state.nargs) && state.optional_args) {
|
|
// WMC - Modder has chosen to ignore this argument
|
|
} else {
|
|
LuaError(L, "%s: Argument %d is an invalid type '%s'; type '%s' expected", state.funcname, state.nargs,
|
|
ade_get_type_string(L, state.nargs), internal::getTableEntry(od.idx).GetName());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
bool get_single_arg(lua_State* L, const get_args_state& state, char fmt, luacpp::LuaTable* t)
|
|
{
|
|
Assertion(fmt == 't', "Invalid character '%c' for table type!", fmt);
|
|
|
|
// Get a table
|
|
if (!luacpp::convert::popValue(L, *t, state.nargs, false)) {
|
|
LuaError(L, "%s: Argument %d is an invalid type '%s'; table expected.", state.funcname, state.nargs,
|
|
ade_get_type_string(L, state.nargs));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool get_single_arg(lua_State* L, const get_args_state& state, char fmt, luacpp::LuaFunction* f)
|
|
{
|
|
Assertion(fmt == 'u', "Invalid character '%c' for function type!", fmt);
|
|
|
|
// Get a function
|
|
if (!luacpp::convert::popValue(L, *f, state.nargs, false)) {
|
|
LuaError(L, "%s: Argument %d is an invalid type '%s'; function expected.", state.funcname, state.nargs,
|
|
ade_get_type_string(L, state.nargs));
|
|
return false;
|
|
}
|
|
// Automatically assign our error function to function values retrieved from the API
|
|
f->setErrorFunction(luacpp::LuaFunction::createFromCFunction(L, ade_friendly_error));
|
|
return true;
|
|
}
|
|
|
|
void set_single_arg(lua_State* L, char fmt, const char* s)
|
|
{
|
|
Assertion(fmt == 's', "Invalid format character '%c' for string type!", fmt);
|
|
// WMC - Isn't working with HookVar for some strange reason
|
|
lua_pushstring(L, s);
|
|
}
|
|
void set_single_arg(lua_State*, char fmt, luacpp::LuaTable* table)
|
|
{
|
|
Assertion(fmt == 't', "Invalid format character '%c' for table type!", fmt);
|
|
table->pushValue();
|
|
}
|
|
void set_single_arg(lua_State*, char fmt, luacpp::LuaFunction* func)
|
|
{
|
|
Assertion(fmt == 'u', "Invalid format character '%c' for function type!", fmt);
|
|
func->pushValue();
|
|
}
|
|
|
|
} // namespace internal
|
|
}
|