summaryrefslogtreecommitdiffstats
path: root/src/Bindings
diff options
context:
space:
mode:
Diffstat (limited to 'src/Bindings')
-rw-r--r--src/Bindings/BindingsProcessor.lua4
-rw-r--r--src/Bindings/LuaState.cpp87
-rw-r--r--src/Bindings/LuaState.h156
-rw-r--r--src/Bindings/ManualBindings_World.cpp2
4 files changed, 208 insertions, 41 deletions
diff --git a/src/Bindings/BindingsProcessor.lua b/src/Bindings/BindingsProcessor.lua
index fba992082..a398f5026 100644
--- a/src/Bindings/BindingsProcessor.lua
+++ b/src/Bindings/BindingsProcessor.lua
@@ -98,7 +98,9 @@ local function OutputLuaStateHelpers(a_Package)
f:write("// This file expects to be included form inside the cLuaState class definition\n")
f:write("\n\n\n\n\n")
for _, item in ipairs(types) do
- f:write("void Push(" .. item.name .. " * a_Value);\n")
+ if not(g_HasCustomPushImplementation[item.name]) then
+ f:write("void Push(" .. item.name .. " * a_Value);\n")
+ end
end
for _, item in ipairs(types) do
f:write("bool GetStackValue(int a_StackPos, Ptr" .. item.lname .. " & a_ReturnedVal);\n")
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index 232432a99..a0fdecb8b 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -211,23 +211,31 @@ void cLuaState::AddPackagePath(const AString & a_PathVariable, const AString & a
-bool cLuaState::LoadFile(const AString & a_FileName)
+bool cLuaState::LoadFile(const AString & a_FileName, bool a_LogWarnings)
{
ASSERT(IsValid());
// Load the file:
int s = luaL_loadfile(m_LuaState, a_FileName.c_str());
- if (ReportErrors(s))
+ if (s != 0)
{
- LOGWARNING("Can't load %s because of an error in file %s", m_SubsystemName.c_str(), a_FileName.c_str());
+ if (a_LogWarnings)
+ {
+ LOGWARNING("Can't load %s because of a load error in file %s: %d (%s)", m_SubsystemName.c_str(), a_FileName.c_str(), s, lua_tostring(m_LuaState, -1));
+ }
+ lua_pop(m_LuaState, 1);
return false;
}
// Execute the globals:
s = lua_pcall(m_LuaState, 0, LUA_MULTRET, 0);
- if (ReportErrors(s))
+ if (s != 0)
{
- LOGWARNING("Error in %s in file %s", m_SubsystemName.c_str(), a_FileName.c_str());
+ if (a_LogWarnings)
+ {
+ LOGWARNING("Can't load %s because of an initialization error in file %s: %d (%s)", m_SubsystemName.c_str(), a_FileName.c_str(), s, lua_tostring(m_LuaState, -1));
+ }
+ lua_pop(m_LuaState, 1);
return false;
}
@@ -446,6 +454,18 @@ void cLuaState::Push(const cPlayer * a_Player)
+void cLuaState::Push(const cLuaState::cRef & a_Ref)
+{
+ ASSERT(IsValid());
+
+ lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, static_cast<int>(a_Ref));
+ m_NumCurrentFunctionArgs += 1;
+}
+
+
+
+
+
void cLuaState::Push(const HTTPRequest * a_Request)
{
ASSERT(IsValid());
@@ -765,14 +785,17 @@ bool cLuaState::GetStackValue(int a_StackPos, double & a_ReturnedVal)
-bool cLuaState::GetStackValue(int a_StackPos, float & a_ReturnedVal)
+bool cLuaState::GetStackValue(int a_StackPos, eBlockFace & a_ReturnedVal)
{
- if (lua_isnumber(m_LuaState, a_StackPos))
+ if (!lua_isnumber(m_LuaState, a_StackPos))
{
- a_ReturnedVal = static_cast<float>(tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal));
- return true;
+ return false;
}
- return false;
+ a_ReturnedVal = static_cast<eBlockFace>(Clamp(
+ static_cast<int>(tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal)),
+ static_cast<int>(BLOCK_FACE_MIN), static_cast<int>(BLOCK_FACE_MAX))
+ );
+ return true;
}
@@ -796,6 +819,50 @@ bool cLuaState::GetStackValue(int a_StackPos, eWeather & a_ReturnedVal)
+bool cLuaState::GetStackValue(int a_StackPos, float & a_ReturnedVal)
+{
+ if (lua_isnumber(m_LuaState, a_StackPos))
+ {
+ a_ReturnedVal = static_cast<float>(tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal));
+ return true;
+ }
+ return false;
+}
+
+
+
+
+
+cLuaState::cStackValue cLuaState::WalkToValue(const AString & a_Name)
+{
+ // There needs to be at least one value on the stack:
+ ASSERT(lua_gettop(m_LuaState) > 0);
+
+ // Iterate over path and replace the top of the stack with the walked element
+ lua_pushvalue(m_LuaState, -1); // Copy the stack value into the "working area"
+ auto path = StringSplit(a_Name, ".");
+ for (const auto & elem: path)
+ {
+ // If the value is not a table, bail out (error):
+ if (!lua_istable(m_LuaState, -1))
+ {
+ lua_pop(m_LuaState, 1);
+ return cStackValue();
+ }
+
+ // Get the next part of the path:
+ lua_getfield(m_LuaState, -1, elem.c_str());
+
+ // Remove the previous value from the stack (keep only the new one):
+ lua_remove(m_LuaState, -2);
+ } // for elem - path[]
+ return std::move(cStackValue(*this));
+}
+
+
+
+
+
bool cLuaState::CallFunction(int a_NumResults)
{
ASSERT (m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first
diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h
index 8a3411d30..cc8214646 100644
--- a/src/Bindings/LuaState.h
+++ b/src/Bindings/LuaState.h
@@ -78,11 +78,14 @@ public:
bool IsValid(void) const {return (m_Ref != LUA_REFNIL); }
/** Allows to use this class wherever an int (i. e. ref) is to be used */
- operator int(void) const { return m_Ref; }
-
+ explicit operator int(void) const { return m_Ref; }
+
protected:
cLuaState * m_LuaState;
int m_Ref;
+
+ // Remove the copy-constructor:
+ cRef(const cRef &) = delete;
} ;
@@ -98,6 +101,12 @@ public:
{
}
+ cTableRef(const cRef & a_TableRef, const char * a_FnName) :
+ m_TableRef(static_cast<int>(a_TableRef)),
+ m_FnName(a_FnName)
+ {
+ }
+
int GetTableRef(void) const { return m_TableRef; }
const char * GetFnName(void) const { return m_FnName; }
} ;
@@ -111,6 +120,61 @@ public:
static const cRet Return; // Use this constant to delimit function args from return values for cLuaState::Call()
+ /** A RAII class for values pushed onto the Lua stack.
+ Will pop the value off the stack in the destructor. */
+ class cStackValue
+ {
+ public:
+ cStackValue(void):
+ m_LuaState(nullptr)
+ {
+ }
+
+ cStackValue(cLuaState & a_LuaState):
+ m_LuaState(a_LuaState)
+ {
+ m_StackLen = lua_gettop(a_LuaState);
+ }
+
+ cStackValue(cStackValue && a_Src):
+ m_LuaState(nullptr),
+ m_StackLen(-1)
+ {
+ std::swap(m_LuaState, a_Src.m_LuaState);
+ std::swap(m_StackLen, a_Src.m_StackLen);
+ }
+
+ ~cStackValue()
+ {
+ if (m_LuaState != nullptr)
+ {
+ auto top = lua_gettop(m_LuaState);
+ ASSERT(m_StackLen == top);
+ lua_pop(m_LuaState, 1);
+ }
+ }
+
+ void Set(cLuaState & a_LuaState)
+ {
+ m_LuaState = a_LuaState;
+ m_StackLen = lua_gettop(a_LuaState);
+ }
+
+ bool IsValid(void) const
+ {
+ return (m_LuaState != nullptr);
+ }
+
+ protected:
+ lua_State * m_LuaState;
+
+ int m_StackLen;
+
+ // Remove the copy-constructor:
+ cStackValue(const cStackValue &) = delete;
+ };
+
+
/** Creates a new instance. The LuaState is not initialized.
a_SubsystemName is used for reporting problems in the console, it is "plugin %s" for plugins,
or "LuaScript" for the cLuaScript template
@@ -151,10 +215,9 @@ public:
void AddPackagePath(const AString & a_PathVariable, const AString & a_Path);
/** Loads the specified file
- Returns false and logs a warning to the console if not successful (but the LuaState is kept open).
- m_SubsystemName is displayed in the warning log message.
- */
- bool LoadFile(const AString & a_FileName);
+ Returns false and optionally logs a warning to the console if not successful (but the LuaState is kept open).
+ m_SubsystemName is displayed in the warning log message. */
+ bool LoadFile(const AString & a_FileName, bool a_LogWarnings = true);
/** Returns true if a_FunctionName is a valid Lua function that can be called */
bool HasFunction(const char * a_FunctionName);
@@ -169,6 +232,7 @@ public:
void Push(const char * a_Value);
void Push(const cItems & a_Items);
void Push(const cPlayer * a_Player);
+ void Push(const cRef & a_Ref);
void Push(const HTTPRequest * a_Request);
void Push(const HTTPTemplateRequest * a_Request);
void Push(const Vector3d & a_Vector);
@@ -178,22 +242,24 @@ public:
// Push a simple value onto the stack (keep alpha-sorted):
void Push(bool a_Value);
+ void Push(cEntity * a_Entity);
+ void Push(cLuaServerHandle * a_ServerHandle);
+ void Push(cLuaTCPLink * a_TCPLink);
+ void Push(cLuaUDPEndpoint * a_UDPEndpoint);
void Push(double a_Value);
void Push(int a_Value);
void Push(void * a_Ptr);
void Push(std::chrono::milliseconds a_time);
- void Push(cLuaServerHandle * a_ServerHandle);
- void Push(cLuaTCPLink * a_TCPLink);
- void Push(cLuaUDPEndpoint * a_UDPEndpoint);
// GetStackValue() retrieves the value at a_StackPos, if it is a valid type. If not, a_Value is unchanged.
// Returns whether value was changed
- // Enum values are clamped to their allowed range.
+ // Enum values are checked for their allowed values and fail if the value is not assigned.
bool GetStackValue(int a_StackPos, AString & a_Value);
bool GetStackValue(int a_StackPos, bool & a_Value);
bool GetStackValue(int a_StackPos, cPluginManager::CommandResult & a_Result);
bool GetStackValue(int a_StackPos, cRef & a_Ref);
bool GetStackValue(int a_StackPos, double & a_Value);
+ bool GetStackValue(int a_StackPos, eBlockFace & a_Value);
bool GetStackValue(int a_StackPos, eWeather & a_Value);
bool GetStackValue(int a_StackPos, float & a_ReturnedVal);
@@ -202,21 +268,53 @@ public:
bool GetStackValue(int a_StackPos, T & a_ReturnedVal, typename std::enable_if<std::is_integral<T>::value>::type * unused = nullptr)
{
UNUSED(unused);
- if (lua_isnumber(m_LuaState, a_StackPos))
+ if (!lua_isnumber(m_LuaState, a_StackPos)) // Also accepts strings representing a number: http://pgl.yoyo.org/luai/i/lua_isnumber
{
- lua_Number Val = tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal);
- if (Val > std::numeric_limits<T>::max())
- {
- return false;
- }
- if (Val < std::numeric_limits<T>::min())
- {
- return false;
- }
- a_ReturnedVal = static_cast<T>(Val);
- return true;
+ return false;
+ }
+ lua_Number Val = lua_tonumber(m_LuaState, a_StackPos);
+ if (Val > std::numeric_limits<T>::max())
+ {
+ return false;
+ }
+ if (Val < std::numeric_limits<T>::min())
+ {
+ return false;
+ }
+ a_ReturnedVal = static_cast<T>(Val);
+ return true;
+ }
+
+ /** Pushes the named value in the table at the top of the stack.
+ a_Name may be a path containing multiple table levels, such as "_G.cChatColor.Blue".
+ If the value is found, it is pushed on top of the stack and the returned cStackValue is valid.
+ If the value is not found, the stack is unchanged and the returned cStackValue is invalid. */
+ cStackValue WalkToValue(const AString & a_Name);
+
+ /** Retrieves the named value in the table at the top of the Lua stack.
+ a_Name may be a path containing multiple table levels, such as "_G.cChatColor.Blue".
+ Returns true if the value was successfully retrieved, false on error. */
+ template <typename T> bool GetNamedValue(const AString & a_Name, T & a_Value)
+ {
+ auto stk = WalkToValue(a_Name);
+ if (!stk.IsValid())
+ {
+ // Name not found
+ return false;
}
- return false;
+ return GetStackValue(-1, a_Value);
+ }
+
+ /** Retrieves the named global value. a_Name may be a path containing multiple table levels, such as "_G.cChatColor.Blue".
+ Returns true if the value was successfully retrieved, false on error. */
+ template <typename T> bool GetNamedGlobal(const AString & a_Name, T & a_Value)
+ {
+ // Push the globals table onto the stack and make it RAII-removed:
+ lua_getglobal(m_LuaState, "_G");
+ cStackValue stk(*this);
+
+ // Get the named global:
+ return GetNamedValue(a_Name, a_Value);
}
// Include the auto-generated Push and GetStackValue() functions:
@@ -229,12 +327,12 @@ public:
template <typename FnT, typename... Args>
bool Call(const FnT & a_Function, Args &&... args)
{
- if (!PushFunction(a_Function))
+ if (!PushFunction(std::forward<const FnT &>(a_Function)))
{
// Pushing the function failed
return false;
}
- return PushCallPop(args...);
+ return PushCallPop(std::forward<Args>(args)...);
}
/** Retrieves a list of values from the Lua stack, starting at the specified index. */
@@ -343,10 +441,10 @@ protected:
/** Variadic template recursor: More params to push. Push them and recurse. */
template <typename T, typename... Args>
- inline bool PushCallPop(T a_Param, Args &&... args)
+ inline bool PushCallPop(T && a_Param, Args &&... args)
{
- Push(a_Param);
- return PushCallPop(args...);
+ Push(std::forward<T>(a_Param));
+ return PushCallPop(std::forward<Args>(args)...);
}
/** Variadic template terminator: If there's nothing more to push, but return values to collect, call the function and collect the returns. */
@@ -363,7 +461,7 @@ protected:
}
// Collect the return values:
- GetStackValues(-NumReturns, args...);
+ GetStackValues(-NumReturns, std::forward<Args>(args)...);
lua_pop(m_LuaState, NumReturns);
// All successful:
diff --git a/src/Bindings/ManualBindings_World.cpp b/src/Bindings/ManualBindings_World.cpp
index ddbebce78..d9590de33 100644
--- a/src/Bindings/ManualBindings_World.cpp
+++ b/src/Bindings/ManualBindings_World.cpp
@@ -490,7 +490,7 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S)
auto task = std::make_shared<cLuaScheduledWorldTask>(*Plugin, FnRef);
Plugin->AddResettable(task);
- World->ScheduleTask(DelayTicks, task);
+ World->ScheduleTask(DelayTicks, static_cast<cWorld::cTaskPtr>(task));
return 0;
}