Files
fs2open.github.com/code/scripting/lua/LuaConvert.cpp
T
asarium f780d9e22a Add ability to dynamically add new SEXPs at runtime
This add a system for adding generic instances of the DynamicSEXP class
to the SEXP system. The only implementation at the moment is the LuaSEXP
which is used by the mn.addSEXP lua API to allow Lua to add new SEXPs.

Since this requires that FRED also runs lua scripts I added a mod table
option to enable scripting in FRED. Since the current scripts are not
built with FRED in mind it would likely break all these scripts if FRED
would be opened with normal scripting enabled.

This fixes #1320.
2017-12-20 10:45:40 +01:00

226 lines
5.3 KiB
C++

#include "LuaConvert.h"
namespace
{
using namespace scripting;
ade_table_entry& getTableEntry(size_t idx) {
return ade_manager::getInstance()->getEntry(idx);
}
}
namespace luacpp {
namespace convert {
namespace internal {
bool isValidIndex(lua_State* state, int index) {
if (1 <= std::abs(index) && std::abs(index) <= lua_gettop(state)) {
return true;
} else {
return false;
}
}
}
void pushValue(lua_State* luaState, const double& value) {
lua_pushnumber(luaState, value);
}
void pushValue(lua_State* luaState, const float& value) {
lua_pushnumber(luaState, value);
}
void pushValue(lua_State* luaState, const int& value) {
lua_pushnumber(luaState, value);
}
void pushValue(lua_State* luaState, const size_t& value) {
lua_pushnumber(luaState, (lua_Number)value);
}
void pushValue(lua_State* luaState, const std::string& value) {
lua_pushlstring(luaState, value.c_str(), value.size());
}
void pushValue(lua_State* luaState, const char* value) {
lua_pushstring(luaState, value);
}
void pushValue(lua_State* luaState, const bool& value) {
lua_pushboolean(luaState, value);
}
void pushValue(lua_State* luaState, const lua_CFunction& value) {
lua_pushcfunction(luaState, value);
}
void pushValue(lua_State* L, const ade_odata& od) {
using namespace scripting;
//WMC - char must be 1 byte, foo.
static_assert(sizeof(char) == 1, "char must be 1 byte!");
//WMC - step by step
//Create new LUA object and get handle
char *newod = (char*)lua_newuserdata(L, od.size + sizeof(ODATA_SIG_TYPE));
//Create or get object metatable
luaL_getmetatable(L, getTableEntry(od.idx).Name);
//Set the metatable for the object
lua_setmetatable(L, -2);
//Copy the actual object data to the Lua object
memcpy(newod, od.buf, od.size);
//Also copy in the unique sig
if (od.sig != NULL)
memcpy(newod + od.size, od.sig, sizeof(ODATA_SIG_TYPE));
else
{
ODATA_SIG_TYPE tempsig = ODATA_SIG_DEFAULT;
memcpy(newod + od.size, &tempsig, sizeof(ODATA_SIG_TYPE));
}
}
bool popValue(lua_State* luaState, int& target, int stackposition, bool remove) {
double temp;
auto ret = popValue(luaState, temp, stackposition, remove);
if (ret) {
target = (int)temp;
}
return ret;
}
bool popValue(lua_State* luaState, size_t& target, int stackposition, bool remove) {
double temp;
auto ret = popValue(luaState, temp, stackposition, remove);
if (ret) {
target = (size_t)temp;
}
return ret;
}
bool popValue(lua_State* luaState, float& target, int stackposition, bool remove) {
double temp;
auto ret = popValue(luaState, temp, stackposition, remove);
if (ret) {
target = (float)temp;
}
return ret;
}
bool popValue(lua_State* luaState, double& target, int stackposition, bool remove) {
if (!internal::isValidIndex(luaState, stackposition)) {
return false;
}
if (!lua_isnumber(luaState, stackposition)) {
return false;
} else {
target = lua_tonumber(luaState, stackposition);
if (remove) {
lua_remove(luaState, stackposition);
}
return true;
}
}
bool popValue(lua_State* luaState, std::string& target, int stackposition, bool remove) {
if (!internal::isValidIndex(luaState, stackposition)) {
return false;
}
if (!lua_isstring(luaState, stackposition)) {
return false;
} else {
size_t size;
const char* string = lua_tolstring(luaState, stackposition, &size);
target.assign(string, size);
if (remove) {
lua_remove(luaState, stackposition);
}
return true;
}
}
bool popValue(lua_State* luaState, bool& target, int stackposition, bool remove) {
if (!internal::isValidIndex(luaState, stackposition)) {
return false;
}
if (!lua_isboolean(luaState, stackposition)) {
return false;
} else {
target = lua_toboolean(luaState, stackposition) != 0;
if (remove) {
lua_remove(luaState, stackposition);
}
return target;
}
}
bool popValue(lua_State* luaState, lua_CFunction& target, int stackposition, bool remove) {
if (!internal::isValidIndex(luaState, stackposition)) {
return false;
}
if (!lua_iscfunction(luaState, stackposition)) {
return false;
} else {
target = lua_tocfunction(luaState, stackposition);
if (remove) {
lua_remove(luaState, stackposition);
}
return true;
}
}
bool popValue(lua_State* L, scripting::ade_odata& od, int stackposition, bool remove) {
//WMC - Get metatable
lua_getmetatable(L, stackposition);
int mtb_ldx = lua_gettop(L);
Assert(!lua_isnil(L, -1));
//Get ID
lua_pushstring(L, "__adeid");
lua_rawget(L, mtb_ldx);
if (lua_tonumber(L, -1) != od.idx)
{
lua_pushstring(L, "__adederivid");
lua_rawget(L, mtb_ldx);
if ((uint)lua_tonumber(L, -1) != od.idx)
{
// Issue the LuaError here since this is the only place where we have all relevant information
LuaError(L, "Argument %d is the wrong type of userdata; '%s' given, but '%s' expected", stackposition, getTableEntry((uint)lua_tonumber(L, -2)).Name, getTableEntry(od.idx).GetName());
return false;
}
lua_pop(L, 1);
}
lua_pop(L, 2);
if (od.size != ODATA_PTR_SIZE)
{
memcpy(od.buf, lua_touserdata(L, stackposition), od.size);
if (od.sig != NULL) {
//WMC - char must be 1
Assert(sizeof(char) == 1);
//WMC - Yuck. Copy sig data.
//Maybe in the future I'll do a packet userdata thing.
(*od.sig) = *(ODATA_SIG_TYPE*)(*(char **)od.buf + od.size);
}
}
else {
(*(void**)od.buf) = lua_touserdata(L, stackposition);
}
if (remove) {
lua_remove(L, stackposition);
}
return true;
}
}
}