2013-08-04 17:11:25 -04:00
|
|
|
|
|
|
|
// LuaState.h
|
|
|
|
|
|
|
|
// Declares the cLuaState class representing the wrapper over lua_State *, provides associated helper functions
|
|
|
|
|
2013-08-06 02:01:00 -04:00
|
|
|
/*
|
|
|
|
The contained lua_State can be either owned or attached.
|
|
|
|
Owned lua_State is created by calling Create() and the cLuaState automatically closes the state
|
|
|
|
Or, lua_State can be attached by calling Attach(), the cLuaState doesn't close such a state
|
2016-06-12 10:53:24 -04:00
|
|
|
If owning a state, trying to attach a state will automatically close the previously owned state.
|
2013-08-06 02:59:54 -04:00
|
|
|
|
2014-07-01 16:19:14 -04:00
|
|
|
Calling a Lua function is done internally by pushing the function using PushFunction(), then pushing the
|
|
|
|
arguments and finally executing CallFunction(). cLuaState automatically keeps track of the number of
|
|
|
|
arguments and the name of the function (for logging purposes). After the call the return values are read from
|
2016-08-21 05:03:10 -04:00
|
|
|
the stack using GetStackValue(). All of this is wrapped in a templated function overloads cLuaState::Call().
|
2013-08-07 08:26:18 -04:00
|
|
|
|
|
|
|
Reference management is provided by the cLuaState::cRef class. This is used when you need to hold a reference to
|
2016-08-21 05:03:10 -04:00
|
|
|
any Lua object across several function calls. The class is RAII-like, with automatic resource management. Note
|
|
|
|
that the cRef object is not inherently thread-safe and is not notified when its cLuaState is closed. For those
|
|
|
|
purposes, cTrackedRef can be used.
|
2016-06-12 10:53:24 -04:00
|
|
|
|
|
|
|
Callbacks management is provided by the cLuaState::cCallback class. Use a GetStackValue() with cCallbackPtr
|
|
|
|
parameter to store the callback, and then at any time you can use the cCallback's Call() templated function
|
|
|
|
to call the callback. The callback management takes care of cLuaState being destroyed - the cCallback object
|
|
|
|
stays valid but doesn't call into Lua code anymore, returning false for "failure" instead.
|
2013-08-06 02:01:00 -04:00
|
|
|
*/
|
2013-08-04 17:11:25 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2013-08-07 08:26:18 -04:00
|
|
|
extern "C"
|
|
|
|
{
|
2013-11-26 12:14:46 -05:00
|
|
|
#include "lua/src/lauxlib.h"
|
2013-08-07 08:26:18 -04:00
|
|
|
}
|
2013-08-04 17:11:25 -04:00
|
|
|
|
2017-01-13 04:31:05 -05:00
|
|
|
#include <atomic>
|
2014-03-11 10:01:17 -04:00
|
|
|
#include "../Vector3.h"
|
2014-07-03 11:49:21 -04:00
|
|
|
#include "../Defines.h"
|
2015-05-10 17:11:30 -04:00
|
|
|
#include "PluginManager.h"
|
2015-05-12 03:20:54 -04:00
|
|
|
#include "LuaState_Typedefs.inc"
|
2014-03-11 10:01:17 -04:00
|
|
|
|
2015-05-12 03:20:54 -04:00
|
|
|
// fwd:
|
2015-04-23 13:41:01 -04:00
|
|
|
class cLuaServerHandle;
|
|
|
|
class cLuaTCPLink;
|
|
|
|
class cLuaUDPEndpoint;
|
2016-06-12 10:53:24 -04:00
|
|
|
class cPluginLua;
|
2017-01-17 16:38:04 -05:00
|
|
|
class cDeadlockDetect;
|
2013-08-06 02:59:54 -04:00
|
|
|
|
2013-08-04 17:11:25 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Encapsulates a Lua state and provides some syntactic sugar for common operations */
|
2013-08-04 17:11:25 -04:00
|
|
|
class cLuaState
|
|
|
|
{
|
|
|
|
public:
|
2013-08-07 08:26:18 -04:00
|
|
|
|
2016-11-10 10:46:31 -05:00
|
|
|
#ifdef _DEBUG
|
|
|
|
/** Asserts that the Lua stack has the same amount of entries when this object is destructed, as when it was constructed.
|
|
|
|
Used for checking functions that should preserve Lua stack balance. */
|
|
|
|
class cStackBalanceCheck
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
cStackBalanceCheck(const char * a_FileName, int a_LineNum, lua_State * a_LuaState, bool a_ShouldLogStack = true):
|
|
|
|
m_FileName(a_FileName),
|
|
|
|
m_LineNum(a_LineNum),
|
|
|
|
m_LuaState(a_LuaState),
|
|
|
|
m_StackPos(lua_gettop(a_LuaState))
|
|
|
|
{
|
|
|
|
if (a_ShouldLogStack)
|
|
|
|
{
|
|
|
|
// DEBUG: If an unbalanced stack is reported, uncommenting the next line can help debug the imbalance
|
|
|
|
// cLuaState::LogStackValues(a_LuaState, Printf("Started checking Lua stack balance, currently %d items:", m_StackPos).c_str());
|
|
|
|
// Since LogStackValues() itself uses the balance check, we must not call it recursively
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-22 15:10:41 -04:00
|
|
|
~cStackBalanceCheck() CAN_THROW
|
2016-11-10 10:46:31 -05:00
|
|
|
{
|
|
|
|
auto currStackPos = lua_gettop(m_LuaState);
|
|
|
|
if (currStackPos != m_StackPos)
|
|
|
|
{
|
|
|
|
LOGD("Lua stack not balanced. Expected %d items, found %d items. Stack watching started in %s:%d",
|
|
|
|
m_StackPos, currStackPos,
|
|
|
|
m_FileName.c_str(), m_LineNum
|
|
|
|
);
|
|
|
|
cLuaState::LogStackValues(m_LuaState);
|
|
|
|
ASSERT(!"Lua stack unbalanced"); // If this assert fires, the Lua stack is inbalanced, check the callstack / m_FileName / m_LineNum
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
const AString m_FileName;
|
|
|
|
int m_LineNum;
|
|
|
|
lua_State * m_LuaState;
|
|
|
|
int m_StackPos;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define STRINGIFY2(X, Y) X##Y
|
|
|
|
#define STRINGIFY(X, Y) STRINGIFY2(X, Y)
|
|
|
|
#define ASSERT_LUA_STACK_BALANCE(...) cStackBalanceCheck STRINGIFY(Check, __COUNTER__)(__FILE__, __LINE__, __VA_ARGS__)
|
|
|
|
#else
|
|
|
|
#define ASSERT_LUA_STACK_BALANCE(...)
|
|
|
|
#endif
|
|
|
|
|
2017-06-09 06:16:31 -04:00
|
|
|
|
|
|
|
/** Makes sure that the Lua state's stack has the same number of elements on destruction as it had on construction of this object (RAII).
|
|
|
|
Can only remove elements, if there are less than expected, throws. */
|
|
|
|
class cStackBalancePopper
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
cStackBalancePopper(cLuaState & a_LuaState):
|
|
|
|
m_LuaState(a_LuaState),
|
|
|
|
m_Count(lua_gettop(a_LuaState))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-06-22 15:10:41 -04:00
|
|
|
~cStackBalancePopper() CAN_THROW
|
2017-06-09 06:16:31 -04:00
|
|
|
{
|
|
|
|
auto curTop = lua_gettop(m_LuaState);
|
|
|
|
if (curTop > m_Count)
|
|
|
|
{
|
|
|
|
// There are some leftover elements, adjust the stack:
|
|
|
|
m_LuaState.LogStackValues(Printf("Re-balancing Lua stack, expected %d values, got %d:", m_Count, curTop).c_str());
|
|
|
|
lua_pop(m_LuaState, curTop - m_Count);
|
|
|
|
}
|
|
|
|
else if (curTop < m_Count)
|
|
|
|
{
|
|
|
|
// This is an irrecoverable error, rather than letting the Lua engine crash undefinedly later on, abort now:
|
|
|
|
LOGERROR("Unable to re-balance Lua stack, there are elements missing. Expected at least %d elements, got %d.", m_Count, curTop);
|
|
|
|
throw std::runtime_error(Printf("Unable to re-balance Lua stack, there are elements missing. Expected at least %d elements, got %d.", m_Count, curTop));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
cLuaState & m_LuaState;
|
|
|
|
int m_Count;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-06-12 10:53:24 -04:00
|
|
|
/** Provides a RAII-style locking for the LuaState.
|
|
|
|
Used mainly by the cPluginLua internals to provide the actual locking for interface operations, such as callbacks. */
|
|
|
|
class cLock
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
cLock(cLuaState & a_LuaState):
|
|
|
|
m_Lock(a_LuaState.m_CS)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
protected:
|
|
|
|
cCSLock m_Lock;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-02-09 12:39:22 -05:00
|
|
|
/** Used for storing references to object in the global registry.
|
|
|
|
Can be bound (contains a reference) or unbound (doesn't contain reference).
|
|
|
|
The reference can also be reset by calling RefStack(). */
|
2013-08-07 08:26:18 -04:00
|
|
|
class cRef
|
|
|
|
{
|
|
|
|
public:
|
2014-02-09 12:39:22 -05:00
|
|
|
/** Creates an unbound reference object. */
|
|
|
|
cRef(void);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Creates a reference in the specified LuaState for object at the specified StackPos */
|
2013-08-07 08:26:18 -04:00
|
|
|
cRef(cLuaState & a_LuaState, int a_StackPos);
|
2015-01-30 15:24:02 -05:00
|
|
|
|
|
|
|
/** Moves the reference from the specified instance into a newly created instance.
|
|
|
|
The old instance is then "!IsValid()". */
|
|
|
|
cRef(cRef && a_FromRef);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2013-08-07 08:26:18 -04:00
|
|
|
~cRef();
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-02-09 12:39:22 -05:00
|
|
|
/** Creates a reference to Lua object at the specified stack pos, binds this object to it.
|
|
|
|
Calls UnRef() first if previously bound to another reference. */
|
|
|
|
void RefStack(cLuaState & a_LuaState, int a_StackPos);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-02-09 12:39:22 -05:00
|
|
|
/** Removes the bound reference, resets the object to Unbound state. */
|
|
|
|
void UnRef(void);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Returns true if the reference is valid */
|
2013-08-07 08:26:18 -04:00
|
|
|
bool IsValid(void) const {return (m_Ref != LUA_REFNIL); }
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Allows to use this class wherever an int (i. e. ref) is to be used */
|
2015-06-17 09:21:20 -04:00
|
|
|
explicit operator int(void) const { return m_Ref; }
|
|
|
|
|
2016-03-02 05:34:39 -05:00
|
|
|
/** Returns the Lua state associated with the value. */
|
|
|
|
lua_State * GetLuaState(void) { return m_LuaState; }
|
|
|
|
|
2016-06-10 15:30:07 -04:00
|
|
|
/** Creates a Lua reference to the specified object instance in the specified Lua state.
|
|
|
|
This is useful to make anti-GC references for objects that were created by Lua and need to stay alive longer than Lua GC would normally guarantee. */
|
|
|
|
template <typename T> void CreateFromObject(cLuaState & a_LuaState, T && a_Object)
|
|
|
|
{
|
|
|
|
a_LuaState.Push(std::forward<T>(a_Object));
|
|
|
|
RefStack(a_LuaState, -1);
|
|
|
|
a_LuaState.Pop();
|
|
|
|
}
|
|
|
|
|
2013-08-07 08:26:18 -04:00
|
|
|
protected:
|
2016-03-02 05:34:39 -05:00
|
|
|
lua_State * m_LuaState;
|
2013-08-07 08:26:18 -04:00
|
|
|
int m_Ref;
|
2015-06-17 09:21:20 -04:00
|
|
|
|
|
|
|
// Remove the copy-constructor:
|
|
|
|
cRef(const cRef &) = delete;
|
2013-08-07 08:26:18 -04:00
|
|
|
} ;
|
2016-02-05 16:45:45 -05:00
|
|
|
|
|
|
|
|
2016-07-06 14:52:04 -04:00
|
|
|
/** Represents a reference to a Lua object that has a tracked lifetime -
|
|
|
|
- when the Lua state to which it belongs is closed, the object is kept alive, but invalidated.
|
|
|
|
Is thread-safe and unload-safe.
|
|
|
|
To receive the cTrackedRef instance from the Lua side, use RefStack() or (better) cLuaState::GetStackValue().
|
|
|
|
Note that instances of this class are tracked in the canon LuaState instance, so that
|
|
|
|
they can be invalidated when the LuaState is unloaded; due to multithreading issues they can only be tracked
|
|
|
|
by-ptr, which has an unfortunate effect of disabling the copy and move constructors. */
|
|
|
|
class cTrackedRef
|
2014-01-11 16:51:10 -05:00
|
|
|
{
|
2016-07-06 14:52:04 -04:00
|
|
|
friend class ::cLuaState;
|
2014-01-11 16:51:10 -05:00
|
|
|
public:
|
2016-07-06 14:52:04 -04:00
|
|
|
/** Creates an unbound ref instance. */
|
|
|
|
cTrackedRef(void);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2016-07-06 14:52:04 -04:00
|
|
|
~cTrackedRef()
|
2015-06-17 09:21:20 -04:00
|
|
|
{
|
2016-07-06 14:52:04 -04:00
|
|
|
Clear();
|
2015-06-17 09:21:20 -04:00
|
|
|
}
|
|
|
|
|
2016-07-06 14:52:04 -04:00
|
|
|
/** Set the contained reference to the object at the specified Lua state's stack position.
|
2017-01-13 04:31:05 -05:00
|
|
|
If another reference has been previously contained, it is Clear()-ed first. */
|
2016-07-06 14:52:04 -04:00
|
|
|
bool RefStack(cLuaState & a_LuaState, int a_StackPos);
|
|
|
|
|
2017-01-13 04:31:05 -05:00
|
|
|
/** Frees the contained reference, if any.
|
|
|
|
Untracks the reference from its canon Lua state. */
|
2016-07-06 14:52:04 -04:00
|
|
|
void Clear(void);
|
|
|
|
|
2017-01-13 04:31:05 -05:00
|
|
|
/** Returns true if the contained reference is valid.
|
|
|
|
(Note that depending on this value is not thread-safe, another thread may invalidate the ref in the meantime. It is meant for quick ASSERTs only). */
|
2016-07-06 14:52:04 -04:00
|
|
|
bool IsValid(void);
|
|
|
|
|
|
|
|
/** Returns true if the reference resides in the specified Lua state.
|
2017-01-13 04:31:05 -05:00
|
|
|
Internally, compares the reference's canon Lua state.
|
|
|
|
(Note that depending on this value is not thread-safe, another thread may modify the ref in the meantime. It is meant for quick ASSERTs only). */
|
2016-07-06 14:52:04 -04:00
|
|
|
bool IsSameLuaState(cLuaState & a_LuaState);
|
|
|
|
|
|
|
|
protected:
|
|
|
|
friend class cLuaState;
|
|
|
|
|
2017-01-13 04:31:05 -05:00
|
|
|
/** The mutex protecting m_Ref against multithreaded access.
|
|
|
|
Actually points to the canon Lua state's m_CriticalSection.
|
|
|
|
Is nullptr when ref is empty (not bound). */
|
|
|
|
std::atomic<cCriticalSection *> m_CS;
|
2016-07-06 14:52:04 -04:00
|
|
|
|
|
|
|
/** Reference to the Lua callback */
|
|
|
|
cRef m_Ref;
|
|
|
|
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2016-07-06 14:52:04 -04:00
|
|
|
/** Invalidates the callback, without untracking it from the cLuaState.
|
|
|
|
Called only from cLuaState when closing the Lua state. */
|
|
|
|
void Invalidate(void);
|
|
|
|
|
|
|
|
/** Returns the internal reference.
|
|
|
|
Only to be used when the cLuaState's CS is held and the cLuaState is known to be valid. */
|
|
|
|
cRef & GetRef() { return m_Ref; }
|
|
|
|
|
|
|
|
/** This class cannot be copied, because it is tracked in the LuaState by-ptr.
|
|
|
|
Use a smart pointer for a copyable object. */
|
|
|
|
cTrackedRef(const cTrackedRef &) = delete;
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2016-07-06 14:52:04 -04:00
|
|
|
/** This class cannot be moved, because it is tracked in the LuaState by-ptr.
|
|
|
|
Use a smart pointer for a copyable object. */
|
|
|
|
cTrackedRef(cTrackedRef &&) = delete;
|
|
|
|
};
|
|
|
|
typedef UniquePtr<cTrackedRef> cTrackedRefPtr;
|
|
|
|
typedef SharedPtr<cTrackedRef> cTrackedRefSharedPtr;
|
|
|
|
|
|
|
|
|
|
|
|
/** Represents a stored callback to Lua that C++ code can call.
|
2016-03-02 05:34:39 -05:00
|
|
|
Is thread-safe and unload-safe.
|
|
|
|
When the Lua state is unloaded, the callback returns an error instead of calling into non-existent code.
|
2016-06-12 10:53:24 -04:00
|
|
|
To receive the callback instance from the Lua side, use RefStack() or (better) cLuaState::GetStackValue()
|
|
|
|
with a cCallbackPtr. Note that instances of this class are tracked in the canon LuaState instance, so that
|
|
|
|
they can be invalidated when the LuaState is unloaded; due to multithreading issues they can only be tracked
|
|
|
|
by-ptr, which has an unfortunate effect of disabling the copy and move constructors. */
|
2016-07-06 14:52:04 -04:00
|
|
|
class cCallback:
|
|
|
|
public cTrackedRef
|
2016-03-02 05:34:39 -05:00
|
|
|
{
|
2016-07-06 14:52:04 -04:00
|
|
|
typedef cTrackedRef Super;
|
|
|
|
|
2016-03-02 05:34:39 -05:00
|
|
|
public:
|
|
|
|
|
2016-07-06 14:52:04 -04:00
|
|
|
cCallback(void) {}
|
2016-03-02 05:34:39 -05:00
|
|
|
|
|
|
|
/** Calls the Lua callback, if still available.
|
|
|
|
Returns true if callback has been called.
|
|
|
|
Returns false if the Lua state isn't valid anymore. */
|
|
|
|
template <typename... Args>
|
|
|
|
bool Call(Args &&... args)
|
|
|
|
{
|
2017-01-13 04:31:05 -05:00
|
|
|
auto cs = m_CS.load();
|
2016-06-12 10:53:24 -04:00
|
|
|
if (cs == nullptr)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
cCSLock Lock(*cs);
|
2016-03-02 05:34:39 -05:00
|
|
|
if (!m_Ref.IsValid())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2016-06-12 10:53:24 -04:00
|
|
|
return cLuaState(m_Ref.GetLuaState()).Call(m_Ref, std::forward<Args>(args)...);
|
2016-03-02 05:34:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Set the contained callback to the function in the specified Lua state's stack position.
|
2016-07-06 14:52:04 -04:00
|
|
|
If a callback has been previously contained, it is unreferenced first.
|
|
|
|
Returns true on success, false on failure (not a function at the specified stack pos). */
|
2016-03-02 05:34:39 -05:00
|
|
|
bool RefStack(cLuaState & a_LuaState, int a_StackPos);
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
2016-06-12 10:53:24 -04:00
|
|
|
/** This class cannot be copied, because it is tracked in the LuaState by-ptr.
|
|
|
|
Use cCallbackPtr for a copyable object. */
|
2016-03-02 05:34:39 -05:00
|
|
|
cCallback(const cCallback &) = delete;
|
|
|
|
|
2016-06-12 10:53:24 -04:00
|
|
|
/** This class cannot be moved, because it is tracked in the LuaState by-ptr.
|
|
|
|
Use cCallbackPtr for a copyable object. */
|
2016-03-02 05:34:39 -05:00
|
|
|
cCallback(cCallback &&) = delete;
|
|
|
|
};
|
2016-06-27 14:49:59 -04:00
|
|
|
typedef UniquePtr<cCallback> cCallbackPtr;
|
|
|
|
typedef SharedPtr<cCallback> cCallbackSharedPtr;
|
2016-03-02 05:34:39 -05:00
|
|
|
|
|
|
|
|
2016-08-14 10:26:31 -04:00
|
|
|
/** Same thing as cCallback, but GetStackValue() won't fail if the callback value is nil.
|
|
|
|
Used for callbacks that are optional - they needn't be present and in such a case they won't get called. */
|
|
|
|
class cOptionalCallback:
|
|
|
|
public cCallback
|
|
|
|
{
|
|
|
|
typedef cCallback Super;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
cOptionalCallback(void) {}
|
|
|
|
|
|
|
|
/** Set the contained callback to the function in the specified Lua state's stack position.
|
|
|
|
If a callback has been previously contained, it is unreferenced first.
|
|
|
|
Returns true on success, false on failure (not a function at the specified stack pos). */
|
|
|
|
bool RefStack(cLuaState & a_LuaState, int a_StackPos);
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
/** This class cannot be copied, because it is tracked in the LuaState by-ptr.
|
|
|
|
Use cCallbackPtr for a copyable object. */
|
|
|
|
cOptionalCallback(const cOptionalCallback &) = delete;
|
|
|
|
|
|
|
|
/** This class cannot be moved, because it is tracked in the LuaState by-ptr.
|
|
|
|
Use cCallbackPtr for a copyable object. */
|
|
|
|
cOptionalCallback(cOptionalCallback &&) = delete;
|
|
|
|
};
|
|
|
|
typedef UniquePtr<cOptionalCallback> cOptionalCallbackPtr;
|
|
|
|
|
|
|
|
|
2016-07-06 14:52:04 -04:00
|
|
|
/** Represents a stored Lua table with callback functions that C++ code can call.
|
|
|
|
Is thread-safe and unload-safe.
|
|
|
|
When Lua state is unloaded, the CallFn() will return failure instead of calling into non-existent code.
|
2016-08-14 10:26:31 -04:00
|
|
|
To receive the cTableRef instance from the Lua side, use RefStack() or (better) cLuaState::GetStackValue()
|
|
|
|
with a cTableRefPtr.
|
|
|
|
Note that instances of this class are tracked in the canon LuaState instance, so that they can be
|
|
|
|
invalidated when the LuaState is unloaded; due to multithreading issues they can only be tracked by-ptr,
|
|
|
|
which has an unfortunate effect of disabling the copy and move constructors. */
|
2016-07-06 14:52:04 -04:00
|
|
|
class cTableRef:
|
|
|
|
public cTrackedRef
|
|
|
|
{
|
|
|
|
typedef cTrackedRef Super;
|
|
|
|
public:
|
|
|
|
cTableRef(void) {}
|
|
|
|
|
|
|
|
/** Calls the Lua function stored under the specified name in the referenced table, if still available.
|
|
|
|
Returns true if callback has been called.
|
|
|
|
Returns false if the Lua state isn't valid anymore, or the function doesn't exist. */
|
|
|
|
template <typename... Args>
|
|
|
|
bool CallTableFn(const char * a_FnName, Args &&... args)
|
|
|
|
{
|
2017-01-13 04:31:05 -05:00
|
|
|
auto cs = m_CS.load();
|
2016-07-06 14:52:04 -04:00
|
|
|
if (cs == nullptr)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
cCSLock Lock(*cs);
|
|
|
|
if (!m_Ref.IsValid())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return cLuaState(m_Ref.GetLuaState()).CallTableFn(m_Ref, a_FnName, std::forward<Args>(args)...);
|
|
|
|
}
|
|
|
|
|
2016-08-23 07:20:43 -04:00
|
|
|
/** Calls the Lua function stored under the specified name in the referenced table, if still available.
|
|
|
|
A "self" parameter is injected in front of all the given parameters and is set to the callback table.
|
|
|
|
Returns true if callback has been called.
|
|
|
|
Returns false if the Lua state isn't valid anymore, or the function doesn't exist. */
|
|
|
|
template <typename... Args>
|
|
|
|
bool CallTableFnWithSelf(const char * a_FnName, Args &&... args)
|
|
|
|
{
|
2017-01-13 04:31:05 -05:00
|
|
|
auto cs = m_CS.load();
|
2016-08-23 07:20:43 -04:00
|
|
|
if (cs == nullptr)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
cCSLock Lock(*cs);
|
|
|
|
if (!m_Ref.IsValid())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return cLuaState(m_Ref.GetLuaState()).CallTableFn(m_Ref, a_FnName, m_Ref, std::forward<Args>(args)...);
|
|
|
|
}
|
|
|
|
|
2016-07-06 14:52:04 -04:00
|
|
|
/** Set the contained reference to the table in the specified Lua state's stack position.
|
|
|
|
If another table has been previously contained, it is unreferenced first.
|
|
|
|
Returns true on success, false on failure (not a table at the specified stack pos). */
|
|
|
|
bool RefStack(cLuaState & a_LuaState, int a_StackPos);
|
|
|
|
};
|
|
|
|
typedef UniquePtr<cTableRef> cTableRefPtr;
|
|
|
|
|
|
|
|
|
2016-08-16 05:55:12 -04:00
|
|
|
/** Represents a parameter that is optional - calling a GetStackValue() with this object will not fail if the value on the Lua stack is nil.
|
|
|
|
Note that the GetStackValue() will still fail if the param is present but of a different type.
|
|
|
|
The class itself is just a marker so that the template magic will select the correct GetStackValue() overload. */
|
|
|
|
template <typename T>
|
|
|
|
class cOptionalParam
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit cOptionalParam(T & a_Dest):
|
|
|
|
m_Dest(a_Dest)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
T & GetDest(void) { return m_Dest; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
T & m_Dest;
|
|
|
|
};
|
|
|
|
|
2016-08-16 07:02:08 -04:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** A dummy class that's used only to delimit function args from return values for cLuaState::Call() */
|
2013-08-08 08:08:21 -04:00
|
|
|
class cRet
|
|
|
|
{
|
|
|
|
} ;
|
|
|
|
static const cRet Return; // Use this constant to delimit function args from return values for cLuaState::Call()
|
2013-08-07 08:26:18 -04:00
|
|
|
|
|
|
|
|
2016-08-16 07:02:08 -04:00
|
|
|
/** A dummy class that's used only to push a constant nil as a function parameter in Call(). */
|
|
|
|
class cNil
|
|
|
|
{
|
|
|
|
};
|
|
|
|
static const cNil Nil; // Use this constant to give a function a nil parameter in Call()
|
|
|
|
|
|
|
|
|
2015-06-17 09:21:20 -04:00
|
|
|
/** 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);
|
|
|
|
}
|
|
|
|
|
2017-06-22 15:10:41 -04:00
|
|
|
~cStackValue() CAN_THROW
|
2015-06-17 09:21:20 -04:00
|
|
|
{
|
|
|
|
if (m_LuaState != nullptr)
|
|
|
|
{
|
2016-08-02 07:12:34 -04:00
|
|
|
ASSERT(m_StackLen == lua_gettop(m_LuaState));
|
2015-06-17 09:21:20 -04:00
|
|
|
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;
|
|
|
|
|
2016-06-12 10:53:24 -04:00
|
|
|
/** Used for debugging, Lua state's stack size is checked against this number to make sure
|
|
|
|
it is the same as when the value was pushed. */
|
2015-06-17 09:21:20 -04:00
|
|
|
int m_StackLen;
|
|
|
|
|
|
|
|
// Remove the copy-constructor:
|
|
|
|
cStackValue(const cStackValue &) = delete;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-08-14 10:26:31 -04:00
|
|
|
/** Represents a table on the Lua stack.
|
|
|
|
Provides easy access to the elements in the table.
|
|
|
|
Note that this class doesn't have cTrackedRef's thread-safeness and unload-safeness, it is expected to be
|
|
|
|
used for immediate queries in API bindings. */
|
|
|
|
class cStackTable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
cStackTable(cLuaState & a_LuaState, int a_StackPos);
|
|
|
|
|
|
|
|
/** Iterates over all array elements in the table consecutively and calls the a_ElementCallback for each.
|
|
|
|
The callback receives the LuaState in which the table resides, and the element's index. The LuaState has
|
|
|
|
the element on top of its stack. If the callback returns true, the iteration is aborted, if it returns
|
|
|
|
false, the iteration continues with the next element. */
|
|
|
|
void ForEachArrayElement(std::function<bool(cLuaState & a_LuaState, int a_Index)> a_ElementCallback) const;
|
|
|
|
|
|
|
|
/** Iterates over all dictionary elements in the table in random order, and calls the a_ElementCallback for
|
|
|
|
each of them.
|
|
|
|
The callback receives the LuaState in which the table reside. The LuaState has the element on top of its
|
|
|
|
stack, and the element's key just below it. If the callback returns true, the iteration is aborted, if it
|
|
|
|
returns false, the iteration continues with the next element. */
|
|
|
|
void ForEachElement(std::function<bool(cLuaState & a_LuaState)> a_ElementCallback) const;
|
|
|
|
|
|
|
|
cLuaState & GetLuaState(void) const { return m_LuaState; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
/** The Lua state in which the table resides. */
|
|
|
|
cLuaState & m_LuaState;
|
|
|
|
|
|
|
|
/** The stack index where the table resides in the Lua state. */
|
|
|
|
int m_StackPos;
|
|
|
|
};
|
|
|
|
typedef UniquePtr<cStackTable> cStackTablePtr;
|
|
|
|
|
|
|
|
|
2013-08-04 17:11:25 -04:00
|
|
|
/** Creates a new instance. The LuaState is not initialized.
|
2014-07-17 16:15:34 -04:00
|
|
|
a_SubsystemName is used for reporting problems in the console, it is "plugin %s" for plugins,
|
2013-08-04 17:11:25 -04:00
|
|
|
or "LuaScript" for the cLuaScript template
|
|
|
|
*/
|
|
|
|
cLuaState(const AString & a_SubsystemName);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2013-08-06 02:01:00 -04:00
|
|
|
/** Creates a new instance. The a_AttachState is attached.
|
|
|
|
Subsystem name is set to "<attached>".
|
|
|
|
*/
|
|
|
|
explicit cLuaState(lua_State * a_AttachState);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2013-08-04 17:11:25 -04:00
|
|
|
~cLuaState();
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Allows this object to be used in the same way as a lua_State *, for example in the LuaLib functions */
|
2013-08-04 17:11:25 -04:00
|
|
|
operator lua_State * (void) { return m_LuaState; }
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2017-01-15 06:54:46 -05:00
|
|
|
/** Creates the m_LuaState, if not created already.
|
|
|
|
This state will be automatically closed in the destructor.
|
2014-03-12 08:05:28 -04:00
|
|
|
The regular Lua libs are registered, but the MCS API is not registered (so that Lua can be used as
|
|
|
|
lite-config as well), use RegisterAPILibs() to do that. */
|
2013-08-04 17:11:25 -04:00
|
|
|
void Create(void);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-03-12 08:05:28 -04:00
|
|
|
/** Registers all the API libraries that MCS provides into m_LuaState. */
|
|
|
|
void RegisterAPILibs(void);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Closes the m_LuaState, if not closed already */
|
2013-08-04 17:11:25 -04:00
|
|
|
void Close(void);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Attaches the specified state. Operations will be carried out on this state, but it will not be closed in the destructor */
|
2013-08-06 02:01:00 -04:00
|
|
|
void Attach(lua_State * a_State);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Detaches a previously attached state. */
|
2013-08-06 02:01:00 -04:00
|
|
|
void Detach(void);
|
2015-11-11 04:32:42 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Returns true if the m_LuaState is valid */
|
2014-10-20 16:55:07 -04:00
|
|
|
bool IsValid(void) const { return (m_LuaState != nullptr); }
|
2015-09-28 15:30:31 -04:00
|
|
|
|
|
|
|
/** Returns the name of the subsystem, as specified when the instance was created. */
|
|
|
|
AString GetSubsystemName(void) const { return m_SubsystemName; }
|
2015-11-11 04:32:42 -05:00
|
|
|
|
2014-02-17 17:12:46 -05:00
|
|
|
/** Adds the specified path to package.<a_PathVariable> */
|
|
|
|
void AddPackagePath(const AString & a_PathVariable, const AString & a_Path);
|
2015-11-11 04:32:42 -05:00
|
|
|
|
2013-08-04 17:11:25 -04:00
|
|
|
/** Loads the specified file
|
2015-06-17 09:21:20 -04:00
|
|
|
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);
|
2015-11-11 04:32:42 -05:00
|
|
|
|
|
|
|
/** Loads the specified string.
|
|
|
|
Returns false and optionally logs a warning to the console if not successful (but the LuaState is kept open).
|
|
|
|
a_FileName is the original filename from where the string was read, and is used only for logging. It may be empty.
|
|
|
|
m_SubsystemName is displayed in the warning log message. */
|
|
|
|
bool LoadString(const AString & a_StringToLoad, const AString & a_FileName, bool a_LogWarnings = true);
|
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Returns true if a_FunctionName is a valid Lua function that can be called */
|
2013-08-08 10:02:07 -04:00
|
|
|
bool HasFunction(const char * a_FunctionName);
|
2015-11-11 04:32:42 -05:00
|
|
|
|
2016-08-21 05:03:10 -04:00
|
|
|
/** Pushes multiple arguments onto the Lua stack. */
|
|
|
|
template <typename Arg1, typename Arg2, typename... Args>
|
|
|
|
void Push(Arg1 && a_Arg1, Arg2 && a_Arg2, Args &&... a_Args)
|
|
|
|
{
|
|
|
|
Push(std::forward<Arg1>(a_Arg1));
|
|
|
|
Push(std::forward<Arg2>(a_Arg2), std::forward<Args>(a_Args)...);
|
|
|
|
}
|
|
|
|
|
2014-06-03 13:29:04 -04:00
|
|
|
// Push a const value onto the stack (keep alpha-sorted):
|
2017-05-09 07:21:03 -04:00
|
|
|
// Note that these functions will make a copy of the actual value, because Lua doesn't have the concept
|
|
|
|
// of "const", and there would be lifetime management problems if they didn't.
|
2013-08-08 08:08:21 -04:00
|
|
|
void Push(const AString & a_String);
|
2016-08-16 05:55:12 -04:00
|
|
|
void Push(const AStringMap & a_Dictionary);
|
2013-08-08 08:08:21 -04:00
|
|
|
void Push(const AStringVector & a_Vector);
|
|
|
|
void Push(const char * a_Value);
|
2016-08-16 07:02:08 -04:00
|
|
|
void Push(const cNil & a_Nil);
|
2015-06-17 09:21:20 -04:00
|
|
|
void Push(const cRef & a_Ref);
|
2014-06-03 13:29:04 -04:00
|
|
|
void Push(const Vector3d & a_Vector);
|
2014-08-22 04:33:15 -04:00
|
|
|
void Push(const Vector3i & a_Vector);
|
2014-06-03 13:29:04 -04:00
|
|
|
|
2015-05-12 03:20:54 -04:00
|
|
|
// Push a simple value onto the stack (keep alpha-sorted):
|
2014-06-03 13:29:04 -04:00
|
|
|
void Push(bool a_Value);
|
2015-06-18 17:30:41 -04:00
|
|
|
void Push(cEntity * a_Entity);
|
|
|
|
void Push(cLuaServerHandle * a_ServerHandle);
|
|
|
|
void Push(cLuaTCPLink * a_TCPLink);
|
|
|
|
void Push(cLuaUDPEndpoint * a_UDPEndpoint);
|
2014-06-03 13:29:04 -04:00
|
|
|
void Push(double a_Value);
|
|
|
|
void Push(int a_Value);
|
2015-09-26 16:54:18 -04:00
|
|
|
void Push(long a_Value);
|
2015-07-29 11:04:03 -04:00
|
|
|
void Push(const UInt32 a_Value);
|
2015-01-11 16:12:26 -05:00
|
|
|
void Push(std::chrono::milliseconds a_time);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2016-06-10 15:30:07 -04:00
|
|
|
/** Pops the specified number of values off the top of the Lua stack. */
|
|
|
|
void Pop(int a_NumValuesToPop = 1);
|
|
|
|
|
2015-04-23 13:41:01 -04:00
|
|
|
// GetStackValue() retrieves the value at a_StackPos, if it is a valid type. If not, a_Value is unchanged.
|
2015-05-19 10:25:18 -04:00
|
|
|
// Returns whether value was changed
|
2015-06-17 09:21:20 -04:00
|
|
|
// Enum values are checked for their allowed values and fail if the value is not assigned.
|
2015-05-19 10:25:18 -04:00
|
|
|
bool GetStackValue(int a_StackPos, AString & a_Value);
|
2016-08-16 05:55:12 -04:00
|
|
|
bool GetStackValue(int a_StackPos, AStringMap & a_Value);
|
2015-05-19 10:25:18 -04:00
|
|
|
bool GetStackValue(int a_StackPos, bool & a_Value);
|
2016-03-02 04:12:43 -05:00
|
|
|
bool GetStackValue(int a_StackPos, cCallback & a_Callback);
|
|
|
|
bool GetStackValue(int a_StackPos, cCallbackPtr & a_Callback);
|
2016-06-27 14:49:59 -04:00
|
|
|
bool GetStackValue(int a_StackPos, cCallbackSharedPtr & a_Callback);
|
2016-08-14 10:26:31 -04:00
|
|
|
bool GetStackValue(int a_StackPos, cOptionalCallback & a_Callback);
|
|
|
|
bool GetStackValue(int a_StackPos, cOptionalCallbackPtr & a_Callback);
|
2015-05-19 10:25:18 -04:00
|
|
|
bool GetStackValue(int a_StackPos, cPluginManager::CommandResult & a_Result);
|
|
|
|
bool GetStackValue(int a_StackPos, cRef & a_Ref);
|
2016-08-14 10:26:31 -04:00
|
|
|
bool GetStackValue(int a_StackPos, cStackTablePtr & a_StackTable);
|
|
|
|
bool GetStackValue(int a_StackPos, cTableRef & a_TableRef);
|
|
|
|
bool GetStackValue(int a_StackPos, cTableRefPtr & a_TableRef);
|
2016-07-06 14:52:04 -04:00
|
|
|
bool GetStackValue(int a_StackPos, cTrackedRef & a_Ref);
|
|
|
|
bool GetStackValue(int a_StackPos, cTrackedRefPtr & a_Ref);
|
|
|
|
bool GetStackValue(int a_StackPos, cTrackedRefSharedPtr & a_Ref);
|
2015-05-19 10:25:18 -04:00
|
|
|
bool GetStackValue(int a_StackPos, double & a_Value);
|
2015-06-17 09:21:20 -04:00
|
|
|
bool GetStackValue(int a_StackPos, eBlockFace & a_Value);
|
2015-05-19 10:25:18 -04:00
|
|
|
bool GetStackValue(int a_StackPos, eWeather & a_Value);
|
|
|
|
bool GetStackValue(int a_StackPos, float & a_ReturnedVal);
|
|
|
|
|
|
|
|
// template to catch all of the various c++ integral types without overload conflicts
|
|
|
|
template <class T>
|
|
|
|
bool GetStackValue(int a_StackPos, T & a_ReturnedVal, typename std::enable_if<std::is_integral<T>::value>::type * unused = nullptr)
|
|
|
|
{
|
|
|
|
UNUSED(unused);
|
2015-06-17 09:21:20 -04:00
|
|
|
if (!lua_isnumber(m_LuaState, a_StackPos)) // Also accepts strings representing a number: http://pgl.yoyo.org/luai/i/lua_isnumber
|
2015-05-19 10:25:18 -04:00
|
|
|
{
|
2015-06-17 09:21:20 -04:00
|
|
|
return false;
|
2015-05-19 10:25:18 -04:00
|
|
|
}
|
2015-06-17 09:21:20 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-08-16 05:55:12 -04:00
|
|
|
/** Retrieves an optional value on the stack - doesn't fail if the stack contains nil instead of the value. */
|
|
|
|
template <typename T>
|
|
|
|
bool GetStackValue(int a_StackPos, cOptionalParam<T> && a_ReturnedVal)
|
|
|
|
{
|
|
|
|
if (lua_isnoneornil(m_LuaState, a_StackPos))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return GetStackValue(a_StackPos, a_ReturnedVal.GetDest());
|
|
|
|
}
|
|
|
|
|
2015-06-17 09:21:20 -04:00
|
|
|
/** Pushes the named value in the table at the top of the stack.
|
2015-11-11 04:32:42 -05:00
|
|
|
a_Name may be a path containing multiple table levels, such as "cChatColor.Blue".
|
2015-06-17 09:21:20 -04:00
|
|
|
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);
|
|
|
|
|
2015-11-11 04:32:42 -05:00
|
|
|
/** Pushes the named value in the global table to the top of the stack.
|
|
|
|
a_Name may be a path containing multiple table levels, such as "cChatColor.Blue".
|
|
|
|
If the value is found in the global table, it is pushed to the 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 WalkToNamedGlobal(const AString & a_Name);
|
|
|
|
|
2015-06-17 09:21:20 -04:00
|
|
|
/** 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 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);
|
2015-05-19 10:25:18 -04:00
|
|
|
}
|
2015-05-12 03:20:54 -04:00
|
|
|
|
|
|
|
// Include the auto-generated Push and GetStackValue() functions:
|
|
|
|
#include "LuaState_Declaration.inc"
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-10-15 12:50:32 -04:00
|
|
|
/** Call the specified Lua function.
|
|
|
|
Returns true if call succeeded, false if there was an error.
|
|
|
|
A special param of cRet & signifies the end of param list and the start of return values.
|
|
|
|
Example call: Call(Fn, Param1, Param2, Param3, cLuaState::Return, Ret1, Ret2) */
|
|
|
|
template <typename FnT, typename... Args>
|
2014-10-16 10:11:35 -04:00
|
|
|
bool Call(const FnT & a_Function, Args &&... args)
|
2014-10-15 12:50:32 -04:00
|
|
|
{
|
2017-06-09 06:16:31 -04:00
|
|
|
cStackBalancePopper balancer(*this);
|
2016-08-16 08:05:03 -04:00
|
|
|
m_NumCurrentFunctionArgs = -1;
|
2015-06-17 09:21:20 -04:00
|
|
|
if (!PushFunction(std::forward<const FnT &>(a_Function)))
|
2014-10-31 14:25:31 -04:00
|
|
|
{
|
|
|
|
// Pushing the function failed
|
|
|
|
return false;
|
|
|
|
}
|
2016-11-10 10:46:31 -05:00
|
|
|
auto res = PushCallPop(std::forward<Args>(args)...);
|
|
|
|
return res;
|
2014-10-15 12:50:32 -04:00
|
|
|
}
|
2014-01-11 16:51:10 -05:00
|
|
|
|
2014-10-15 12:50:32 -04:00
|
|
|
/** Retrieves a list of values from the Lua stack, starting at the specified index. */
|
2016-08-16 05:55:12 -04:00
|
|
|
template <typename Arg1, typename... Args>
|
|
|
|
inline bool GetStackValues(int a_StartStackPos, Arg1 && a_Arg1, Args &&... args)
|
2014-10-15 12:50:32 -04:00
|
|
|
{
|
2016-08-16 05:55:12 -04:00
|
|
|
if (!GetStackValue(a_StartStackPos, std::forward<Arg1>(a_Arg1)))
|
2015-05-19 10:25:18 -04:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2016-08-16 05:55:12 -04:00
|
|
|
return GetStackValues(a_StartStackPos + 1, std::forward<Args>(args)...);
|
2014-10-15 12:50:32 -04:00
|
|
|
}
|
2013-08-08 10:02:07 -04:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Returns true if the specified parameters on the stack are of the specified usertable type; also logs warning if not. Used for static functions */
|
2013-11-22 10:49:38 -05:00
|
|
|
bool CheckParamUserTable(int a_StartParam, const char * a_UserTable, int a_EndParam = -1);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Returns true if the specified parameters on the stack are of the specified usertype; also logs warning if not. Used for regular functions */
|
2013-08-07 08:26:18 -04:00
|
|
|
bool CheckParamUserType(int a_StartParam, const char * a_UserType, int a_EndParam = -1);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Returns true if the specified parameters on the stack are tables; also logs warning if not */
|
2013-08-07 08:26:18 -04:00
|
|
|
bool CheckParamTable(int a_StartParam, int a_EndParam = -1);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Returns true if the specified parameters on the stack are numbers; also logs warning if not */
|
2013-08-07 08:26:18 -04:00
|
|
|
bool CheckParamNumber(int a_StartParam, int a_EndParam = -1);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2015-12-16 09:04:47 -05:00
|
|
|
/** Returns true if the specified parameters on the stack are bools; also logs warning if not */
|
|
|
|
bool CheckParamBool(int a_StartParam, int a_EndParam = -1);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Returns true if the specified parameters on the stack are strings; also logs warning if not */
|
2013-11-22 14:11:24 -05:00
|
|
|
bool CheckParamString(int a_StartParam, int a_EndParam = -1);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Returns true if the specified parameters on the stack are functions; also logs warning if not */
|
2014-01-19 17:45:26 -05:00
|
|
|
bool CheckParamFunction(int a_StartParam, int a_EndParam = -1);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-02-11 09:03:35 -05:00
|
|
|
/** Returns true if the specified parameters on the stack are functions or nils; also logs warning if not */
|
|
|
|
bool CheckParamFunctionOrNil(int a_StartParam, int a_EndParam = -1);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Returns true if the specified parameter on the stack is nil (indicating an end-of-parameters) */
|
2013-08-07 08:26:18 -04:00
|
|
|
bool CheckParamEnd(int a_Param);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2017-06-24 05:58:06 -04:00
|
|
|
/** Returns true if the first parameter is an instance of the expected class name.
|
|
|
|
Returns false and logs a special warning ("wrong calling convention") if not. */
|
|
|
|
bool CheckParamSelf(const char * a_SelfClassName);
|
|
|
|
|
2015-03-21 13:17:26 -04:00
|
|
|
bool IsParamUserType(int a_Param, AString a_UserType);
|
|
|
|
|
|
|
|
bool IsParamNumber(int a_Param);
|
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** If the status is nonzero, prints the text on the top of Lua stack and returns true */
|
2013-08-04 17:11:25 -04:00
|
|
|
bool ReportErrors(int status);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** If the status is nonzero, prints the text on the top of Lua stack and returns true */
|
2013-08-04 17:11:25 -04:00
|
|
|
static bool ReportErrors(lua_State * a_LuaState, int status);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Logs all items in the current stack trace to the server console */
|
2014-03-19 17:55:47 -04:00
|
|
|
void LogStackTrace(int a_StartingDepth = 0);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Logs all items in the current stack trace to the server console */
|
2014-03-19 17:55:47 -04:00
|
|
|
static void LogStackTrace(lua_State * a_LuaState, int a_StartingDepth = 0);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Returns the type of the item on the specified position in the stack */
|
2013-08-21 14:06:37 -04:00
|
|
|
AString GetTypeText(int a_StackPos);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Calls the function specified by its name, with arguments copied off the foreign state.
|
|
|
|
If successful, keeps the return values on the stack and returns their number.
|
|
|
|
If unsuccessful, returns a negative number and keeps the stack position unchanged. */
|
|
|
|
int CallFunctionWithForeignParams(
|
|
|
|
const AString & a_FunctionName,
|
|
|
|
cLuaState & a_SrcLuaState,
|
|
|
|
int a_SrcParamStart,
|
|
|
|
int a_SrcParamEnd
|
|
|
|
);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Copies objects on the stack from the specified state.
|
2016-05-30 19:01:55 -04:00
|
|
|
Only numbers, bools, strings, API classes and simple tables containing these (recursively) are copied.
|
|
|
|
a_NumAllowedNestingLevels specifies how many table nesting levels are allowed, copying fails if there's a deeper table.
|
2014-01-21 16:59:08 -05:00
|
|
|
If successful, returns the number of objects copied.
|
|
|
|
If failed, returns a negative number and rewinds the stack position. */
|
2016-05-30 19:01:55 -04:00
|
|
|
int CopyStackFrom(cLuaState & a_SrcLuaState, int a_SrcStart, int a_SrcEnd, int a_NumAllowedNestingLevels = 16);
|
|
|
|
|
|
|
|
/** Copies a table at the specified stack index of the source Lua state to the top of this Lua state's stack.
|
|
|
|
a_NumAllowedNestingLevels specifies how many table nesting levels are allowed, copying fails if there's a deeper table.
|
|
|
|
Returns true if successful, false on failure.
|
|
|
|
Can copy only simple values - numbers, bools, strings and recursively simple tables. */
|
|
|
|
bool CopyTableFrom(cLuaState & a_SrcLuaState, int a_TableIdx, int a_NumAllowedNestingLevels);
|
|
|
|
|
|
|
|
/** Copies a single value from the specified stack index of the source Lua state to the top of this Lua state's stack.
|
|
|
|
a_NumAllowedNestingLevels specifies how many table nesting levels are allowed, copying fails if there's a deeper table.
|
|
|
|
Returns true if the value was copied, false on failure. */
|
|
|
|
bool CopySingleValueFrom(cLuaState & a_SrcLuaState, int a_StackIdx, int a_NumAllowedNestingLevels);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Reads the value at the specified stack position as a string and sets it to a_String. */
|
|
|
|
void ToString(int a_StackPos, AString & a_String);
|
|
|
|
|
|
|
|
/** Logs all the elements' types on the API stack, with an optional header for the listing. */
|
2016-06-10 15:30:07 -04:00
|
|
|
void LogStackValues(const char * a_Header = nullptr);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Logs all the elements' types on the API stack, with an optional header for the listing. */
|
2016-06-10 15:30:07 -04:00
|
|
|
static void LogStackValues(lua_State * a_LuaState, const char * a_Header = nullptr);
|
|
|
|
|
|
|
|
/** Returns the canon Lua state (the primary cLuaState instance that was used to create, rather than attach, the lua_State structure).
|
|
|
|
Returns nullptr if the canon Lua state cannot be queried. */
|
2017-01-09 09:56:16 -05:00
|
|
|
cLuaState * QueryCanonLuaState(void) const;
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2016-08-23 07:20:43 -04:00
|
|
|
/** Outputs to log a warning about API call being unable to read its parameters from the stack,
|
|
|
|
logs the stack trace and stack values. */
|
|
|
|
void LogApiCallParamFailure(const char * a_FnName, const char * a_ParamNames);
|
|
|
|
|
2017-01-17 16:38:04 -05:00
|
|
|
/** Adds this object's CS to the DeadlockDetect's tracked CSs. */
|
|
|
|
void TrackInDeadlockDetect(cDeadlockDetect & a_DeadlockDetect);
|
|
|
|
|
|
|
|
/** Removes this object's CS from the DeadlockDetect's tracked CSs. */
|
|
|
|
void UntrackInDeadlockDetect(cDeadlockDetect & a_DeadlockDetect);
|
|
|
|
|
2013-08-04 17:11:25 -04:00
|
|
|
protected:
|
2014-10-15 12:50:32 -04:00
|
|
|
|
2016-06-12 10:53:24 -04:00
|
|
|
cCriticalSection m_CS;
|
|
|
|
|
2013-08-04 17:11:25 -04:00
|
|
|
lua_State * m_LuaState;
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** If true, the state is owned by this object and will be auto-Closed. False => attached state */
|
2013-08-06 02:01:00 -04:00
|
|
|
bool m_IsOwned;
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2013-08-04 17:11:25 -04:00
|
|
|
/** The subsystem name is used for reporting errors to the console, it is either "plugin %s" or "LuaScript"
|
2016-03-02 05:34:39 -05:00
|
|
|
whatever is given to the constructor. */
|
2013-08-04 17:11:25 -04:00
|
|
|
AString m_SubsystemName;
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Name of the currently pushed function (for the Push / Call chain) */
|
2013-08-06 02:59:54 -04:00
|
|
|
AString m_CurrentFunctionName;
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Number of arguments currently pushed (for the Push / Call chain) */
|
2013-08-06 02:59:54 -04:00
|
|
|
int m_NumCurrentFunctionArgs;
|
2014-01-11 16:51:10 -05:00
|
|
|
|
2016-07-06 14:52:04 -04:00
|
|
|
/** The tracked references.
|
|
|
|
The cLuaState will invalidate all of these when it is about to be closed.
|
|
|
|
Protected against multithreaded access by m_CSTrackedRefs. */
|
|
|
|
std::vector<cTrackedRef *> m_TrackedRefs;
|
2016-03-02 05:34:39 -05:00
|
|
|
|
2016-07-06 14:52:04 -04:00
|
|
|
/** Protects m_TrackedRefs against multithreaded access. */
|
|
|
|
cCriticalSection m_CSTrackedRefs;
|
2016-03-02 05:34:39 -05:00
|
|
|
|
|
|
|
|
2016-07-06 14:52:04 -04:00
|
|
|
/** Call the Lua function specified by name in the table stored as a reference.
|
|
|
|
Returns true if call succeeded, false if there was an error (not a table ref, function name not found).
|
|
|
|
A special param of cRet & signifies the end of param list and the start of return values.
|
|
|
|
Example call: CallTableFn(TableRef, "FnName", Param1, Param2, Param3, cLuaState::Return, Ret1, Ret2) */
|
|
|
|
template <typename... Args>
|
|
|
|
bool CallTableFn(const cRef & a_TableRef, const char * a_FnName, Args &&... args)
|
|
|
|
{
|
|
|
|
if (!PushFunction(a_TableRef, a_FnName))
|
|
|
|
{
|
|
|
|
// Pushing the function failed
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return PushCallPop(std::forward<Args>(args)...);
|
|
|
|
}
|
|
|
|
|
2014-10-15 12:50:32 -04:00
|
|
|
/** Variadic template terminator: If there's nothing more to push / pop, just call the function.
|
|
|
|
Note that there are no return values either, because those are prefixed by a cRet value, so the arg list is never empty. */
|
|
|
|
bool PushCallPop(void)
|
|
|
|
{
|
|
|
|
return CallFunction(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Variadic template recursor: More params to push. Push them and recurse. */
|
2014-10-19 12:45:32 -04:00
|
|
|
template <typename T, typename... Args>
|
2015-06-17 09:21:20 -04:00
|
|
|
inline bool PushCallPop(T && a_Param, Args &&... args)
|
2014-10-15 12:50:32 -04:00
|
|
|
{
|
2015-06-17 09:21:20 -04:00
|
|
|
Push(std::forward<T>(a_Param));
|
2016-08-16 08:05:03 -04:00
|
|
|
m_NumCurrentFunctionArgs += 1;
|
2015-06-17 09:21:20 -04:00
|
|
|
return PushCallPop(std::forward<Args>(args)...);
|
2014-10-15 12:50:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Variadic template terminator: If there's nothing more to push, but return values to collect, call the function and collect the returns. */
|
|
|
|
template <typename... Args>
|
2014-10-16 10:11:35 -04:00
|
|
|
bool PushCallPop(cLuaState::cRet, Args &&... args)
|
2014-10-15 12:50:32 -04:00
|
|
|
{
|
|
|
|
// Calculate the number of return values (number of args left):
|
2015-01-31 10:44:14 -05:00
|
|
|
int NumReturns = sizeof...(args);
|
2014-10-15 12:50:32 -04:00
|
|
|
|
|
|
|
// Call the function:
|
|
|
|
if (!CallFunction(NumReturns))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Collect the return values:
|
2015-06-17 09:21:20 -04:00
|
|
|
GetStackValues(-NumReturns, std::forward<Args>(args)...);
|
2014-10-15 12:50:32 -04:00
|
|
|
lua_pop(m_LuaState, NumReturns);
|
|
|
|
|
|
|
|
// All successful:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Variadic template terminator: If there are no more values to get, bail out.
|
|
|
|
This function is not available in the public API, because it's an error to request no values directly; only internal functions can do that.
|
|
|
|
If you get a compile error saying this function is not accessible, check your calling code, you aren't reading any stack values. */
|
2015-05-19 10:25:18 -04:00
|
|
|
bool GetStackValues(int a_StartingStackPos)
|
2014-10-15 12:50:32 -04:00
|
|
|
{
|
2015-05-19 10:25:18 -04:00
|
|
|
return true;
|
2014-10-15 12:50:32 -04:00
|
|
|
}
|
|
|
|
|
2014-01-11 16:51:10 -05:00
|
|
|
/** Pushes the function of the specified name onto the stack.
|
|
|
|
Returns true if successful. Logs a warning on failure (incl. m_SubsystemName)
|
|
|
|
*/
|
|
|
|
bool PushFunction(const char * a_FunctionName);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-09-03 17:05:03 -04:00
|
|
|
/** Pushes a function that has been saved as a reference.
|
|
|
|
Returns true if successful. Logs a warning on failure
|
|
|
|
*/
|
2016-06-12 12:24:01 -04:00
|
|
|
bool PushFunction(const cRef & a_FnRef);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2016-07-06 14:52:04 -04:00
|
|
|
/** Pushes a function that is stored under the specified name in a table that has been saved as a reference.
|
|
|
|
Returns true if successful. */
|
|
|
|
bool PushFunction(const cRef & a_TableRef, const char * a_FnName);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-21 16:59:08 -05:00
|
|
|
/** Pushes a usertype of the specified class type onto the stack */
|
2015-05-12 03:20:54 -04:00
|
|
|
// void PushUserType(void * a_Object, const char * a_Type);
|
2014-01-11 16:51:10 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
Calls the function that has been pushed onto the stack by PushFunction(),
|
|
|
|
with arguments pushed by PushXXX().
|
2016-11-10 10:46:31 -05:00
|
|
|
Returns true if successful, returns false and logs a warning on failure.
|
|
|
|
Pops the function params, the function itself and the error handler off the stack.
|
|
|
|
If successful, leaves a_NumReturnValues new values on Lua stack, corresponding to the return values.
|
|
|
|
On failure, leaves no new values on the Lua stack.
|
2014-01-11 16:51:10 -05:00
|
|
|
*/
|
|
|
|
bool CallFunction(int a_NumReturnValues);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-01-11 17:10:40 -05:00
|
|
|
/** Used as the error reporting function for function calls */
|
|
|
|
static int ReportFnCallErrors(lua_State * a_LuaState);
|
2015-05-16 10:19:18 -04:00
|
|
|
|
|
|
|
/** Tries to break into the MobDebug debugger, if it is installed. */
|
|
|
|
static int BreakIntoDebugger(lua_State * a_LuaState);
|
2016-03-02 05:34:39 -05:00
|
|
|
|
2016-07-06 14:52:04 -04:00
|
|
|
/** Adds the specified reference to tracking.
|
|
|
|
The reference will be invalidated when this Lua state is about to be closed. */
|
|
|
|
void TrackRef(cTrackedRef & a_Ref);
|
2016-03-02 05:34:39 -05:00
|
|
|
|
2016-07-06 14:52:04 -04:00
|
|
|
/** Removes the specified reference from tracking.
|
|
|
|
The reference will no longer be invalidated when this Lua state is about to be closed. */
|
|
|
|
void UntrackRef(cTrackedRef & a_Ref);
|
2013-08-04 17:11:25 -04:00
|
|
|
} ;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-09-28 15:30:31 -04:00
|
|
|
|
|
|
|
/** Keeps track of all create cLuaState instances.
|
|
|
|
Can query each for the amount of currently used memory. */
|
|
|
|
class cLuaStateTracker
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
/** Adds the specified Lua state to the internal list of LuaStates. */
|
|
|
|
static void Add(cLuaState & a_LuaState);
|
|
|
|
|
|
|
|
/** Deletes the specified Lua state from the internal list of LuaStates. */
|
|
|
|
static void Del(cLuaState & a_LuaState);
|
|
|
|
|
|
|
|
/** Returns the statistics for all the registered LuaStates. */
|
|
|
|
static AString GetStats(void);
|
|
|
|
|
|
|
|
protected:
|
|
|
|
typedef cLuaState * cLuaStatePtr;
|
|
|
|
typedef std::vector<cLuaStatePtr> cLuaStatePtrs;
|
|
|
|
|
|
|
|
/** The internal list of LuaStates.
|
|
|
|
Protected against multithreaded access by m_CSLuaStates. */
|
|
|
|
cLuaStatePtrs m_LuaStates;
|
|
|
|
|
|
|
|
/** Protects m_LuaStates against multithreaded access. */
|
|
|
|
cCriticalSection m_CSLuaStates;
|
|
|
|
|
|
|
|
|
|
|
|
/** Returns the single instance of this class. */
|
|
|
|
static cLuaStateTracker & Get(void);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|