MegaGlest/source/shared_lib/sources/lua/lua_script.cpp
2016-11-26 15:46:32 +01:00

1146 lines
35 KiB
C++

// ==============================================================
// This file is part of Glest Shared Library (www.glest.org)
//
// Copyright (C) 2001-2008 Martiño Figueroa
//
// You can redistribute this code and/or modify it under
// the terms of the GNU General Public License as published
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#include "lua_script.h"
#include <stdexcept>
#include "conversion.h"
#include "util.h"
#include "platform_util.h"
#include "leak_dumper.h"
using namespace std;
using namespace Shared::Util;
namespace Shared { namespace Lua {
//
// This class wraps streflop for LuaScript. We need to toggle the data type
// for streflop to use when calling into LUA as streflop may corrupt some
// numeric values passed from Lua otherwise
//
class Lua_STREFLOP_Wrapper {
public:
Lua_STREFLOP_Wrapper() {
#ifdef USE_STREFLOP
streflop_init<streflop::Double>();
#endif
}
~Lua_STREFLOP_Wrapper() {
#ifdef USE_STREFLOP
streflop_init<streflop::Simple>();
#endif
}
};
// =====================================================
// class LuaScript
// =====================================================
bool LuaScript::disableSandbox = false;
bool LuaScript::debugModeEnabled = false;
LuaScript::LuaScript() {
Lua_STREFLOP_Wrapper streflopWrapper;
currentLuaFunction = "";
currentLuaFunctionIsValid = false;
sandboxWrapperFunctionName = "";
sandboxCode = "";
luaState= luaL_newstate();
luaL_openlibs(luaState);
if(luaState == NULL) {
throw megaglest_runtime_error("Can not allocate lua state");
}
argumentCount= -1;
if(disableSandbox == false) {
lua_getglobal(luaState, "os");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "execute");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "rename");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "remove");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "exit");
lua_getglobal(luaState, "io");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "open");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "close");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "write");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "read");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "flush");
lua_pushnil(luaState);
lua_setglobal(luaState, "loadfile");
lua_pushnil(luaState);
lua_setglobal(luaState, "dofile");
lua_pushnil(luaState);
lua_setglobal(luaState, "getfenv");
lua_pushnil(luaState);
lua_setglobal(luaState, "getmetatable");
lua_pushnil(luaState);
lua_setglobal(luaState, "load");
lua_pushnil(luaState);
lua_setglobal(luaState, "loadfile");
lua_pushnil(luaState);
lua_setglobal(luaState, "loadstring");
lua_pushnil(luaState);
lua_setglobal(luaState, "rawequal");
lua_pushnil(luaState);
lua_setglobal(luaState, "rawget");
lua_pushnil(luaState);
lua_setglobal(luaState, "rawset");
lua_pushnil(luaState);
lua_setglobal(luaState, "setfenv");
lua_pushnil(luaState);
lua_setglobal(luaState, "setmetatable");
lua_pop(luaState, 1);
}
}
void LuaScript::DumpGlobals()
{
LuaHandle *L = luaState;
// push the first key (nil = beginning of table)
#if LUA_VERSION_NUM <= 501
lua_pushnil(L);
#endif
// lua_next will:
// 1 - pop the key
// 2 - push the next key
// 3 - push the value at that key
// ... so the key will be at index -2 and the value at index -1
#if LUA_VERSION_NUM > 501
lua_pushglobaltable(L);
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
#else
while (lua_next(L, LUA_GLOBALSINDEX) != 0) {
#endif
// get type of key and value
int key_type = lua_type(L, -2);
int value_type = lua_type(L, -1);
// support only string keys
// globals aren't likely to have a non-string key, but just to be certain ...
if (key_type != LUA_TSTRING) {
lua_pop(L, 1); // pop the value so that the top contains the key for the next iteration
continue;
}
// support only number, boolean and string values
if (value_type != LUA_TNUMBER &&
value_type != LUA_TBOOLEAN &&
value_type != LUA_TSTRING) {
lua_pop(L, 1); // again, pop the value before going to the next loop iteration
continue;
}
// get the key as a string
string key_string = lua_tostring(L, -2); // no copy required - we already know this is a string
// do not support variables that start with '_'
// lua has some predefined values like _VERSION. They all start with underscore
if (!key_string.size()) { // this again is highly unlikely, but still ...
lua_pop(L, 1);
continue;
}
if (key_string[0] == '_') {
lua_pop(L, 1);
continue;
}
string value_string;
// convert the value to a string. This depends on its type
switch (value_type) {
case LUA_TSTRING:
case LUA_TNUMBER:
// numbers can be converted to strings
// get the value as a string (this requires a copy because traversing tables
// uses the top of the stack as an index. If conversion from a number to string
// happens, the top of the stack will be altered and the table index will become invalid)
lua_pushvalue(L, -1);
value_string = lua_tostring(L, -1);
lua_pop(L, 1);
break;
case LUA_TBOOLEAN:
value_string = lua_toboolean(L, -1) == 0 ? "false" : "true";
break;
}
// enclose the value in "" if it is a string
if (value_type == LUA_TSTRING) {
value_string = "\"" + value_string + "\"";
}
// resulting line. Somehow save this and when you need to restore it, just
// call luaL_dostring with that line.
//SaveLine(key_string + " = " + value_string); // Pop the value so the index remains on top of the stack for the next iteration
printf("Found global LUA var: %s = %s\n",key_string.c_str(),value_string.c_str());
lua_pop(L, 1);
}
#if LUA_VERSION_NUM > 501
lua_pop(L, 1);
#endif
}
void LuaScript::saveGame(XmlNode *rootNode) {
std::map<string,string> mapTagReplacements;
//try{
LuaHandle *L = luaState;
// push the first key (nil = beginning of table)
#if LUA_VERSION_NUM <= 501
lua_pushnil(L);
#endif
// lua_next will:
// 1 - pop the key
// 2 - push the next key
// 3 - push the value at that key
// ... so the key will be at index -2 and the value at index -1
#if LUA_VERSION_NUM > 501
lua_pushglobaltable(L);
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
#else
while (lua_next(L, LUA_GLOBALSINDEX) != 0) {
#endif
// get type of key and value
int key_type = lua_type(L, -2);
int value_type = lua_type(L, -1);
if(LuaScript::debugModeEnabled == true) printf("LUA save key_type = %d, value_type = %d for var [%s]\n",key_type,value_type,lua_tostring(L, -2));
// support only string keys
// globals aren't likely to have a non-string key, but just to be certain ...
if (key_type != LUA_TSTRING) {
lua_pop(L, 1); // pop the value so that the top contains the key for the next iteration
continue;
}
// support only number, boolean and string values
if (value_type != LUA_TNUMBER &&
value_type != LUA_TBOOLEAN &&
value_type != LUA_TSTRING &&
value_type != LUA_TTABLE) {
lua_pop(L, 1); // again, pop the value before going to the next loop iteration
continue;
}
// get the key as a string
string key_string = lua_tostring(L, -2); // no copy required - we already know this is a string
if(LuaScript::debugModeEnabled == true) printf("key_string [%s]\n",key_string.c_str());
// do not support variables that start with '_'
// lua has some predefined values like _VERSION. They all start with underscore
if (!key_string.size()) { // this again is highly unlikely, but still ...
lua_pop(L, 1);
continue;
}
if (key_string[0] == '_') {
lua_pop(L, 1);
continue;
}
bool skipTable = false;
// The first pair is the tables key type,value
// The second pair is the tables value type,value
vector<pair<pair<int,string>, pair<int,string> > > tableList;
string value_string;
// convert the value to a string. This depends on its type
switch (value_type) {
case LUA_TSTRING:
case LUA_TNUMBER:
// numbers can be converted to strings
// get the value as a string (this requires a copy because traversing tables
// uses the top of the stack as an index. If conversion from a number to string
// happens, the top of the stack will be altered and the table index will become invalid)
lua_pushvalue(L, -1);
value_string = lua_tostring(L, -1);
lua_pop(L, 1);
break;
case LUA_TBOOLEAN:
value_string = lua_toboolean(L, -1) == 0 ? "false" : "true";
break;
case LUA_TTABLE:
{
int tableItemCount = 0;
if(LuaScript::debugModeEnabled == true) printf("================ LUA TABLE DETECTED - START =================\n");
for (lua_pushnil(L); lua_next(L, -2) ;) {
tableItemCount++;
if(LuaScript::debugModeEnabled == true) printf("LUA TABLE loop A\n");
int tableKeyType = lua_type(L, -2);
int tableValueType = lua_type(L, -1);
if(LuaScript::debugModeEnabled == true) printf("LUA TABLE loop item type [%s] key: %d value type: %d\n",lua_typename(L, tableValueType),tableKeyType,tableValueType);
switch (tableValueType) {
case LUA_TSTRING:
case LUA_TNUMBER:
case LUA_TBOOLEAN:
break;
default:
skipTable = true;
break;
}
if(skipTable == false) {
// Stack: value, key, table
std :: string value = "";
if(!lua_isnil(L, -1)) {
if(LuaScript::debugModeEnabled == true) printf("LUA TABLE loop B\n");
lua_pushvalue(L, -1);
if(LuaScript::debugModeEnabled == true) printf("LUA TABLE loop C\n");
if(tableValueType == LUA_TBOOLEAN ) {
value = lua_toboolean(L, -1) == 0 ? "false" : "true";
}
else {
value = lua_tostring (L, -1);
}
if(LuaScript::debugModeEnabled == true) printf("LUA TABLE loop D\n");
lua_pop (L, 1);
}
lua_pop (L, 1);
if(LuaScript::debugModeEnabled == true) printf("LUA TABLE value [%s]\n",value.c_str());
// Stack: key, table
lua_pushvalue(L, -1);
// Stack: key, key, table
std :: string key = lua_tostring(L, -1);
lua_pop(L, 1);
// Stack: key, table
//std :: cout << key << "" << value << "\ n";
if(LuaScript::debugModeEnabled == true) printf("[%s] [%s]\n",key.c_str(),value.c_str());
if(value_string != "") {
value_string += "|||";
}
char szBuf[8096]="";
snprintf(szBuf,8096,"[%s] [%s]",key.c_str(),value.c_str());
//value_string += szBuf;
//vector<pair<pair<int,string>, pair<int,string>> > tableList;
tableList.push_back(make_pair(make_pair(tableKeyType,key),make_pair(tableValueType,value)));
}
else {
if(LuaScript::debugModeEnabled == true) printf("***WARNING*** SKIPPING LUA TABLE because it has an unsupported embedded type: %d [%s]\n",tableValueType, lua_typename(L, tableValueType));
lua_pop(L, 1);
}
}
if(tableItemCount < 1) {
if(LuaScript::debugModeEnabled == true) printf("Skipping lua table tableItemCount = %d\n",tableItemCount);
skipTable = true;
}
if(LuaScript::debugModeEnabled == true) printf("---------------------------- LUA TABLE DETECTED - END ----------------------------\n");
}
break;
}
// enclose the value in "" if it is a string
//if (value_type == LUA_TSTRING) {
//value_string = "\"" + value_string + "\"";
//}
if(skipTable == true) {
if(LuaScript::debugModeEnabled == true) printf("#2 SKIPPING TABLE\n");
}
else {
//vector<pair<pair<int,string>, pair<int,string>> > tableList;
if(tableList.empty() == false) {
XmlNode *luaScriptNode = rootNode->addChild("LuaScript");
luaScriptNode->addAttribute("variable",key_string, mapTagReplacements);
luaScriptNode->addAttribute("value_type",intToStr(value_type), mapTagReplacements);
for(unsigned int i = 0; i < tableList.size(); ++i) {
pair<pair<int,string>, pair<int,string> > &item = tableList[i];
XmlNode *luaScriptTableNode = luaScriptNode->addChild("Table");
luaScriptTableNode->addAttribute("key_type",intToStr(item.first.first), mapTagReplacements);
luaScriptTableNode->addAttribute("key",item.first.second, mapTagReplacements);
luaScriptTableNode->addAttribute("value",item.second.second, mapTagReplacements);
luaScriptTableNode->addAttribute("value_type",intToStr(item.second.first), mapTagReplacements);
}
}
else {
// resulting line. Somehow save this and when you need to restore it, just
// call luaL_dostring with that line.
//SaveLine(key_string + " = " + value_string); // Pop the value so the index remains on top of the stack for the next iteration
//printf("Found global LUA var: %s = %s\n",key_string.c_str(),value_string.c_str());
XmlNode *luaScriptNode = rootNode->addChild("LuaScript");
luaScriptNode->addAttribute("variable",key_string, mapTagReplacements);
luaScriptNode->addAttribute("value",value_string, mapTagReplacements);
luaScriptNode->addAttribute("value_type",intToStr(value_type), mapTagReplacements);
}
}
lua_pop(L, 1);
}
#if LUA_VERSION_NUM > 501
lua_pop(L, 1);
#endif
//}
//catch(const exception &ex) {
// abort();
//}
}
void LuaScript::loadGame(const XmlNode *rootNode) {
if(LuaScript::debugModeEnabled) printf("START [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
vector<XmlNode *> luaScriptNodeList = rootNode->getChildList("LuaScript");
if(LuaScript::debugModeEnabled) printf("luaScriptNodeList.size(): %d\n",(int)luaScriptNodeList.size());
for(unsigned int i = 0; i < luaScriptNodeList.size(); ++i) {
XmlNode *node = luaScriptNodeList[i];
string variable = node->getAttribute("variable")->getValue();
int value_type = node->getAttribute("value_type")->getIntValue();
if(LuaScript::debugModeEnabled) printf(" index #: %u [%s] [%d]\n",i,variable.c_str(),value_type);
switch (value_type) {
case LUA_TSTRING:
if(LuaScript::debugModeEnabled) printf(" value [%s]\n",node->getAttribute("value")->getValue().c_str());
lua_pushstring( luaState, node->getAttribute("value")->getValue().c_str() );
break;
case LUA_TNUMBER:
if(LuaScript::debugModeEnabled) printf(" value [%s]\n",node->getAttribute("value")->getValue().c_str());
lua_pushnumber( luaState, node->getAttribute("value")->getFloatValue() );
break;
case LUA_TBOOLEAN:
if(LuaScript::debugModeEnabled) printf(" value [%s]\n",node->getAttribute("value")->getValue().c_str());
lua_pushboolean( luaState, node->getAttribute("value")->getBoolValue() );
break;
case LUA_TTABLE:
{
if(LuaScript::debugModeEnabled == true) printf("================ LUA TABLE DETECTED - START =================\n");
lua_newtable(luaState); /* We will pass a table */
vector<XmlNode *> luaScriptTableNode = node->getChildList("Table");
if(LuaScript::debugModeEnabled) printf("luaScriptTableNode.size(): %d\n",(int)luaScriptTableNode.size());
for(unsigned int j = 0; j < luaScriptTableNode.size(); ++j) {
XmlNode *nodeTable = luaScriptTableNode[j];
int key_type = nodeTable->getAttribute("key_type")->getIntValue();
if(LuaScript::debugModeEnabled == true) printf("Table item key_type: %d [%s]\n",key_type,lua_typename(luaState, key_type));
switch (key_type) {
case LUA_TSTRING:
if(LuaScript::debugModeEnabled) printf(" table item key [%s]\n",nodeTable->getAttribute("key")->getValue().c_str());
lua_pushstring( luaState, nodeTable->getAttribute("key")->getValue().c_str() );
break;
case LUA_TNUMBER:
if(LuaScript::debugModeEnabled) printf(" table item key [%s]\n",nodeTable->getAttribute("key")->getValue().c_str());
lua_pushnumber( luaState, nodeTable->getAttribute("key")->getFloatValue() );
break;
case LUA_TBOOLEAN:
if(LuaScript::debugModeEnabled) printf(" table item key [%s]\n",nodeTable->getAttribute("key")->getValue().c_str());
lua_pushboolean( luaState, nodeTable->getAttribute("key")->getBoolValue() );
break;
}
int value_type = nodeTable->getAttribute("value_type")->getIntValue();
if(LuaScript::debugModeEnabled == true) printf("Table item value_type: %d [%s]\n",value_type,lua_typename(luaState, value_type));
switch (value_type) {
case LUA_TSTRING:
if(LuaScript::debugModeEnabled) printf(" table item value [%s]\n",nodeTable->getAttribute("value")->getValue().c_str());
lua_pushstring( luaState, nodeTable->getAttribute("value")->getValue().c_str() );
break;
case LUA_TNUMBER:
if(LuaScript::debugModeEnabled) printf(" table item value [%s]\n",nodeTable->getAttribute("value")->getValue().c_str());
lua_pushnumber( luaState, nodeTable->getAttribute("value")->getFloatValue() );
break;
case LUA_TBOOLEAN:
if(LuaScript::debugModeEnabled) printf(" table item value [%s]\n",nodeTable->getAttribute("value")->getValue().c_str());
lua_pushboolean( luaState, nodeTable->getAttribute("value")->getBoolValue() );
break;
}
lua_rawset(luaState, -3); /* Stores the pair in the table */
}
if(LuaScript::debugModeEnabled == true) printf("----------------- LUA TABLE DETECTED - END -----------------\n");
}
break;
}
lua_setglobal( luaState, variable.c_str() );
}
}
LuaScript::~LuaScript() {
Lua_STREFLOP_Wrapper streflopWrapper;
// LuaInterface.LuaTable luatab;
//
// luatab = lua.GetTable("_G");
//
//
// foreach (DictionaryEntry d in luatab)
//
// {
//
// Console.WriteLine("{0} -> {1}", d.Key, d.Value);
//
// }
//DumpGlobals();
lua_close(luaState);
}
void LuaScript::loadCode(string code, string name){
Lua_STREFLOP_Wrapper streflopWrapper;
//printf("Code [%s]\nName [%s]\n",code.c_str(),name.c_str());
int errorCode= luaL_loadbuffer(luaState, code.c_str(), code.length(), name.c_str());
if(errorCode != 0 ) {
printf("=========================================================\n");
printf("Error loading lua code: %s\n",errorToString(errorCode).c_str());
printf("Function name [%s]\ncode:\n%s\n",name.c_str(),code.c_str());
printf("=========================================================\n");
throw megaglest_runtime_error("Error loading lua code: " + errorToString(errorCode),true);
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] name [%s], errorCode = %d\n",__FILE__,__FUNCTION__,__LINE__,name.c_str(),errorCode);
//run code
errorCode= lua_pcall(luaState, 0, 0, 0);
if(errorCode !=0 ) {
printf("=========================================================\n");
printf("Error calling lua pcall: %s\n",errorToString(errorCode).c_str());
printf("=========================================================\n");
throw megaglest_runtime_error("Error initializing lua: " + errorToString(errorCode),true);
}
//const char *errMsg = lua_tostring(luaState, -1);
//printf("END of call to Name [%s]\n",name.c_str());
if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] name [%s], errorCode = %d\n",__FILE__,__FUNCTION__,__LINE__,name.c_str(),errorCode);
}
void LuaScript::setSandboxWrapperFunctionName(string name) {
sandboxWrapperFunctionName = name;
}
void LuaScript::setSandboxCode(string code) {
sandboxCode = code;
}
int LuaScript::runCode(string code) {
Lua_STREFLOP_Wrapper streflopWrapper;
int errorCode = luaL_dostring(luaState,code.c_str());
return errorCode;
}
void LuaScript::beginCall(string functionName) {
Lua_STREFLOP_Wrapper streflopWrapper;
currentLuaFunction = functionName;
if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] functionName [%s]\n",__FILE__,__FUNCTION__,__LINE__,functionName.c_str());
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] functionName [%s]\n",__FILE__,__FUNCTION__,__LINE__,functionName.c_str());
//string funcLuaFunction = functionName;
// if(sandboxWrapperFunctionName != "" && sandboxCode != "") {
// int errorCode= runCode(sandboxCode);
// if(errorCode !=0 ) {
// throw megaglest_runtime_error("Error calling lua function [" + currentLuaFunction + "] error: " + errorToString(errorCode));
// }
// //functionName = sandboxWrapperFunctionName;
// }
lua_getglobal(luaState, functionName.c_str());
currentLuaFunctionIsValid = lua_isfunction(luaState,lua_gettop(luaState));
//printf("currentLuaFunctionIsValid = %d functionName [%s]\n",currentLuaFunctionIsValid,functionName.c_str());
argumentCount= 0;
}
void LuaScript::endCall() {
Lua_STREFLOP_Wrapper streflopWrapper;
if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] currentLuaFunction [%s], currentLuaFunctionIsValid = %d\n",__FILE__,__FUNCTION__,__LINE__,currentLuaFunction.c_str(),currentLuaFunctionIsValid);
if(currentLuaFunctionIsValid == true) {
if(sandboxWrapperFunctionName != "" && sandboxCode != "") {
//lua_pushstring(luaState, currentLuaFunction.c_str()); // push 1st argument, the real lua function
//argumentCount = 1;
string safeWrapper = sandboxWrapperFunctionName + " [[" + currentLuaFunction + "()]]";
printf("Trying to execute [%s]\n",safeWrapper.c_str());
int errorCode= runCode(safeWrapper);
if(errorCode !=0 ) {
throw megaglest_runtime_error("Error calling lua function [" + currentLuaFunction + "] error: " + errorToString(errorCode),true);
}
//printf("Trying to execute [%s]\n",currentLuaFunction.c_str());
//lua_getglobal(luaState, sandboxWrapperFunctionName.c_str());
//argumentCount = 1;
//lua_pushstring( luaState, currentLuaFunction.c_str() );
// int errorCode= lua_pcall(luaState, argumentCount, 0, 0);
// if(errorCode !=0 ) {
// throw megaglest_runtime_error("Error calling lua function [" + currentLuaFunction + "] error: " + errorToString(errorCode));
// }
}
else {
int errorCode= lua_pcall(luaState, argumentCount, 0, 0);
if(errorCode !=0 ) {
throw megaglest_runtime_error("Error calling lua function [" + currentLuaFunction + "] error: " + errorToString(errorCode),true);
}
}
}
else
{
lua_pcall(luaState, argumentCount, 0, 0);
}
}
void LuaScript::registerFunction(LuaFunction luaFunction, string functionName) {
Lua_STREFLOP_Wrapper streflopWrapper;
if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] functionName [%s]\n",__FILE__,__FUNCTION__,__LINE__,functionName.c_str());
lua_pushcfunction(luaState, luaFunction);
lua_setglobal(luaState, functionName.c_str());
}
string LuaScript::errorToString(int errorCode) {
Lua_STREFLOP_Wrapper streflopWrapper;
string error;
switch(errorCode){
case LUA_ERRSYNTAX:
error+= "Syntax error";
break;
case LUA_ERRRUN:
error+= "Runtime error";
break;
case LUA_ERRMEM:
error+= "Memory allocation error";
break;
case LUA_ERRERR:
error+= "Error while running the error handler";
break;
default:
error+= "Unknown LUA error" + intToStr(errorCode);
break;
}
error += string(": ")+luaL_checkstring(luaState, -1);
return error;
}
// =====================================================
// class LuaArguments
// =====================================================
LuaArguments::LuaArguments(lua_State *luaState){
Lua_STREFLOP_Wrapper streflopWrapper;
this->luaState= luaState;
returnCount= 0;
}
int LuaArguments::getInt(int argumentIndex) const{
Lua_STREFLOP_Wrapper streflopWrapper;
if(!lua_isnumber(luaState, argumentIndex)) {
throwLuaError("Can not get int from Lua state");
}
int result = (int)luaL_checkinteger(luaState, argumentIndex);
return result;
}
float LuaArguments::getFloat(int argumentIndex) const {
Lua_STREFLOP_Wrapper streflopWrapper;
if(!lua_isnumber(luaState, argumentIndex)) {
throwLuaError("Can not get int from Lua state");
}
float result = static_cast<float>(luaL_checknumber(luaState, argumentIndex));
return result;
}
Vec2f LuaArguments::getVec2f(int argumentIndex) const {
Lua_STREFLOP_Wrapper streflopWrapper;
Vec2f v;
if(!lua_istable(luaState, argumentIndex)){
throwLuaError("Can not get vec2f from Lua state, value on the stack is not a table");
}
#if LUA_VERSION_NUM > 501
if(lua_rawlen(luaState, argumentIndex)!=2){
#else
if(luaL_getn(luaState, argumentIndex)!=2){
#endif
throwLuaError("Can not get vec2f from Lua state, array size not 2");
}
//string stackString = getStackText();
//printf("Lua Stack:\n%s\n",stackString.c_str());
lua_rawgeti(luaState, argumentIndex, 1);
//printf("xa = %s argumentIndex = %d\n",lua_tostring(luaState, argumentIndex),argumentIndex);
//v.x= (int)luaL_checkinteger(luaState, argumentIndex);
v.x= static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
//printf("X = %d\n",v.x);
lua_rawgeti(luaState, argumentIndex, 2);
//printf("ya = %s\n",lua_tostring(luaState, argumentIndex));
//v.y= (int)luaL_checkinteger(luaState, argumentIndex);
v.y= static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
//printf("Y = %d\n",v.y);
return v;
}
Vec3f LuaArguments::getVec3f(int argumentIndex) const {
Lua_STREFLOP_Wrapper streflopWrapper;
Vec3f v;
if(!lua_istable(luaState, argumentIndex)){
throwLuaError("Can not get vec3f from Lua state, value on the stack is not a table");
}
#if LUA_VERSION_NUM > 501
if(lua_rawlen(luaState, argumentIndex)!=3){
#else
if(luaL_getn(luaState, argumentIndex)!=3){
#endif
throwLuaError("Can not get vec3f from Lua state, array size not 3");
}
//string stackString = getStackText();
//printf("Lua Stack:\n%s\n",stackString.c_str());
lua_rawgeti(luaState, argumentIndex, 1);
//printf("xa = %s argumentIndex = %d\n",lua_tostring(luaState, argumentIndex),argumentIndex);
//v.x= (int)luaL_checkinteger(luaState, argumentIndex);
v.x= static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
//printf("X = %d\n",v.x);
lua_rawgeti(luaState, argumentIndex, 2);
//printf("ya = %s\n",lua_tostring(luaState, argumentIndex));
//v.y= (int)luaL_checkinteger(luaState, argumentIndex);
v.y= static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
//printf("Y = %d\n",v.y);
lua_rawgeti(luaState, argumentIndex, 3);
//printf("ya = %s\n",lua_tostring(luaState, argumentIndex));
//v.y= (int)luaL_checkinteger(luaState, argumentIndex);
v.z= static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
return v;
}
Vec4f LuaArguments::getVec4f(int argumentIndex) const {
Lua_STREFLOP_Wrapper streflopWrapper;
Vec4f v;
if(!lua_istable(luaState, argumentIndex)){
throwLuaError("Can not get vec4f from Lua state, value on the stack is not a table");
}
#if LUA_VERSION_NUM > 501
if(lua_rawlen(luaState, argumentIndex)!=4){
#else
if(luaL_getn(luaState, argumentIndex)!=4){
#endif
throwLuaError("Can not get vec4f from Lua state, array size not 4");
}
//string stackString = getStackText();
//printf("Lua Stack:\n%s\n",stackString.c_str());
lua_rawgeti(luaState, argumentIndex, 1);
//printf("xa = %s argumentIndex = %d\n",lua_tostring(luaState, argumentIndex),argumentIndex);
//v.x= (int)luaL_checkinteger(luaState, argumentIndex);
v.x= static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
//printf("X = %d\n",v.x);
lua_rawgeti(luaState, argumentIndex, 2);
//printf("ya = %s\n",lua_tostring(luaState, argumentIndex));
//v.y= (int)luaL_checkinteger(luaState, argumentIndex);
v.y= static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
//printf("Y = %d\n",v.y);
lua_rawgeti(luaState, argumentIndex, 3);
//printf("ya = %s\n",lua_tostring(luaState, argumentIndex));
//v.y= (int)luaL_checkinteger(luaState, argumentIndex);
v.z= static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
lua_rawgeti(luaState, argumentIndex, 4);
//printf("ya = %s\n",lua_tostring(luaState, argumentIndex));
//v.y= (int)luaL_checkinteger(luaState, argumentIndex);
v.w= static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
return v;
}
string LuaArguments::getString(int argumentIndex) const{
Lua_STREFLOP_Wrapper streflopWrapper;
if(!lua_isstring(luaState, argumentIndex)){
throwLuaError("Can not get string from Lua state");
}
return luaL_checkstring(luaState, argumentIndex);
}
void * LuaArguments::getGenericData(int argumentIndex) const{
Lua_STREFLOP_Wrapper streflopWrapper;
if(lua_isstring(luaState, argumentIndex)) {
const char *result = luaL_checkstring(luaState, argumentIndex);
//printf("\nGENERIC param %d is a string, %s!\n",argumentIndex,result);
return (void *)result;
}
//else if(lua_isnumber(luaState, argumentIndex)) {
// double result = luaL_checknumber(luaState, argumentIndex);
// printf("\nGENERIC param %d is a double, %f!\n",argumentIndex,result);
// return (void *)result;
//}
else if(lua_isnumber(luaState, argumentIndex)) {
lua_Integer result = luaL_checkinteger(luaState, argumentIndex);
//printf("\nGENERIC param %d is an int, %d!\n",argumentIndex,(int)result);
return (void *)result;
}
else {
//printf("\nGENERIC param %d is a NULL!\n",argumentIndex);
return NULL;
}
}
Vec2i LuaArguments::getVec2i(int argumentIndex) const{
Lua_STREFLOP_Wrapper streflopWrapper;
Vec2i v;
if(!lua_istable(luaState, argumentIndex)){
throwLuaError("Can not get vec2i from Lua state, value on the stack is not a table");
}
#if LUA_VERSION_NUM > 501
if(lua_rawlen(luaState, argumentIndex)!=2){
#else
if(luaL_getn(luaState, argumentIndex)!=2){
#endif
throwLuaError("Can not get vec2i from Lua state, array size not 2");
}
//string stackString = getStackText();
//printf("Lua Stack:\n%s\n",stackString.c_str());
lua_rawgeti(luaState, argumentIndex, 1);
//printf("xa = %s argumentIndex = %d\n",lua_tostring(luaState, argumentIndex),argumentIndex);
//v.x= (int)luaL_checkinteger(luaState, argumentIndex);
v.x= (int)lua_tointeger(luaState, argumentIndex);
lua_pop(luaState, 1);
//printf("X = %d\n",v.x);
lua_rawgeti(luaState, argumentIndex, 2);
//printf("ya = %s\n",lua_tostring(luaState, argumentIndex));
//v.y= (int)luaL_checkinteger(luaState, argumentIndex);
v.y= (int)lua_tointeger(luaState, argumentIndex);
lua_pop(luaState, 1);
//printf("Y = %d\n",v.y);
return v;
}
Vec4i LuaArguments::getVec4i(int argumentIndex) const {
Lua_STREFLOP_Wrapper streflopWrapper;
Vec4i v;
if(!lua_istable(luaState, argumentIndex)){
throwLuaError("Can not get vec4i from Lua state, value on the stack is not a table");
}
#if LUA_VERSION_NUM > 501
if(lua_rawlen(luaState, argumentIndex) != 4 ) {
#else
if(luaL_getn(luaState, argumentIndex) != 4) {
#endif
throwLuaError("Can not get vec4i from Lua state, array size not 4");
}
lua_rawgeti(luaState, argumentIndex, 1);
v.x= (int)luaL_checkinteger(luaState, argumentIndex);
lua_pop(luaState, 1);
lua_rawgeti(luaState, argumentIndex, 2);
v.y= (int)luaL_checkinteger(luaState, argumentIndex);
lua_pop(luaState, 1);
lua_rawgeti(luaState, argumentIndex, 3);
v.z= (int)luaL_checkinteger(luaState, argumentIndex);
lua_pop(luaState, 1);
lua_rawgeti(luaState, argumentIndex, 4);
v.w= (int)luaL_checkinteger(luaState, argumentIndex);
lua_pop(luaState, 1);
return v;
}
void LuaArguments::returnInt(int value){
Lua_STREFLOP_Wrapper streflopWrapper;
++returnCount;
lua_pushinteger(luaState, value);
}
void LuaArguments::returnFloat(float value){
Lua_STREFLOP_Wrapper streflopWrapper;
++returnCount;
lua_pushnumber(luaState, value);
}
void LuaArguments::returnString(const string &value){
Lua_STREFLOP_Wrapper streflopWrapper;
++returnCount;
lua_pushstring(luaState, value.c_str());
}
void LuaArguments::returnVec2i(const Vec2i &value){
//Lua_STREFLOP_Wrapper streflopWrapper;
++returnCount;
lua_newtable(luaState);
lua_pushnumber(luaState, value.x);
lua_rawseti(luaState, -2, 1);
lua_pushnumber(luaState, value.y);
lua_rawseti(luaState, -2, 2);
}
void LuaArguments::returnVec4i(const Vec4i &value) {
//Lua_STREFLOP_Wrapper streflopWrapper;
++returnCount;
lua_newtable(luaState);
lua_pushnumber(luaState, value.x);
lua_rawseti(luaState, -2, 1);
lua_pushnumber(luaState, value.y);
lua_rawseti(luaState, -2, 2);
lua_pushnumber(luaState, value.z);
lua_rawseti(luaState, -2, 3);
lua_pushnumber(luaState, value.w);
lua_rawseti(luaState, -2, 4);
}
void LuaArguments::returnVectorInt(const vector<int> &value) {
//Lua_STREFLOP_Wrapper streflopWrapper;
++returnCount;
lua_newtable(luaState);
for(unsigned int i = 0; i < value.size(); ++i) {
lua_pushnumber(luaState, value[i]);
lua_rawseti(luaState, -2, i+1);
}
}
string LuaArguments::getStackText() const {
Lua_STREFLOP_Wrapper streflopWrapper;
string stackString;
int stackSize = lua_gettop(luaState);
//build stack string
for(int i= 1; i<=stackSize; ++i){
stackString+= "-" + intToStr(i) + ": ";
if(lua_isnumber(luaState, -i)){
stackString+= "Number: " + doubleToStr(luaL_checknumber(luaState, -i ));
}
else if(lua_isstring(luaState, -i)){
stackString+= "String: " + string(luaL_checkstring(luaState, -i));
}
else if(lua_istable(luaState, -i)){
//int tableLen = 0;
#if LUA_VERSION_NUM > 501
int tableLen = lua_rawlen(luaState, -i);
#else
int tableLen = luaL_getn(luaState, -i);
#endif
stackString+= "Table (" + intToStr(tableLen) + ")\n";
// for(unsigned int j = 1; j < tableLen; ++j) {
// stackString+= "entry# " + intToStr(j) + ", value = " + lua_tostring(luaState, -i) + "\n";
// }
// int j = 1;
// lua_pushnil(luaState); // The initial key for the traversal.
//
// printf("start loop\n");
//
// while (lua_next(luaState, -2)!=0) {
// printf("in loop j = %d\n",j);
//
// const char* Param=lua_tostring(luaState, -1);
//
// printf("passed in loop j = %d Param [%s]\n",j,(Param != NULL ? Param : "<nil>"));
//
// if (Param!=NULL) {
// stackString+= "entry# " + intToStr(j) + ", value = " + Param + "\n";
// }
//
// // Remove the value, keep the key for the next iteration.
// lua_pop(luaState, 1);
// j++;
// }
// const int len = lua_objlen( luaState, -i );
// printf("Table Len = %d\n",len);
//
// for ( int j = 1; j <= len; ++j ) {
// printf("A Table\n");
//
// lua_pushinteger( luaState, j );
//
// printf("B Table\n");
//
// lua_gettable( luaState, -2 );
//
// printf("C Table\n");
//
// //v.push_back( lua_tointeger( L, -1 ) );
// const char *value = lua_tostring( luaState, -1 );
// printf("D Table value = %s\n",(value != NULL ? value : "<nil>"));
//
// //v.push_back( lua_tointeger( L, -1 ) );
// const char *value2 = lua_tostring( luaState, -2 );
// printf("E Table value2 = %s\n",(value2 != NULL ? value2 : "<nil>"));
//
// value2 = lua_tostring( luaState, -3 );
// printf("F Table value2 = %s\n",(value2 != NULL ? value2 : "<nil>"));
//
// value2 = lua_tostring( luaState, 0 );
// printf("G Table value2 = %s\n",(value2 != NULL ? value2 : "<nil>"));
//
// value2 = lua_tostring( luaState, 1 );
// printf("H Table value2 = %s\n",(value2 != NULL ? value2 : "<nil>"));
//
// stackString+= "entry# " + intToStr(j) + ", value = " + (value != NULL ? value : "<nil>") + "\n";
//
// printf("E Table\n");
//
// lua_pop( luaState, 1 );
// }
}
else
{
stackString+= "Unknown";
}
stackString+= "\n";
}
return stackString;
}
void LuaArguments::throwLuaError(const string &message) const{
Lua_STREFLOP_Wrapper streflopWrapper;
string stackString = getStackText();
throw megaglest_runtime_error("Lua error: " + message + "\n\nLua Stack:\n" + stackString,true);
}
}}//end namespace