11 #include "lua/src/lualib.h" 14 #undef TOLUA_TEMPLATE_BIND 15 #include "tolua++/include/tolua++.h" 17 #include "ManualBindings.h" 18 #include "DeprecatedBindings.h" 20 #include "../Entities/Entity.h" 21 #include "../BlockEntities/BlockEntity.h" 22 #include "../DeadlockDetect.h" 31 #define lua_tostring(L, i) lua_tolstring(L, (i), nullptr) 74 auto itr = inst.m_CanonStates.find(a_LuaState);
75 if (itr == inst.m_CanonStates.end())
88 ASSERT(inst.m_CanonStates.find(a_LuaState) == inst.m_CanonStates.end());
89 inst.m_CanonStates[a_LuaState.operator lua_State *()] = &a_LuaState;
98 auto itr = inst.m_CanonStates.find(a_LuaState);
99 ASSERT(itr != inst.m_CanonStates.end());
100 inst.m_CanonStates.erase(itr);
115 return canonLuaStates;
128 auto & Instance = Get();
129 cCSLock Lock(Instance.m_CSLuaStates);
130 Instance.m_LuaStates.push_back(&a_LuaState);
139 auto & Instance = Get();
140 cCSLock Lock(Instance.m_CSLuaStates);
141 Instance.m_LuaStates.erase(
143 Instance.m_LuaStates.begin(), Instance.m_LuaStates.end(),
146 return (&a_LuaState == a_StoredLuaState);
149 Instance.m_LuaStates.end()
159 auto & Instance = Get();
160 cCSLock Lock(Instance.m_CSLuaStates);
163 for (
auto state: Instance.m_LuaStates)
166 if (!state->Call(
"collectgarbage",
"count", cLuaState::Return, Mem))
168 res.append(
Printf(
"Cannot query memory for state \"%s\"\n", state->GetSubsystemName().c_str()));
172 res.append(
Printf(
"State \"%s\" is using %d KiB of memory\n", state->GetSubsystemName().c_str(), Mem));
176 res.append(
Printf(
"Total memory used by Lua: %d KiB\n", Total));
216 m_CS = &(canonState->m_CS);
228 lua_State * luaState =
nullptr;
230 auto cs =
m_CS.load();
245 if (luaState ==
nullptr)
258 auto cs =
m_CS.load();
273 auto cs =
m_CS.load();
284 if (canonState ==
nullptr)
297 auto cs =
m_CS.load();
306 LOGD(
"%s: Inconsistent callback at %p, has a CS but an invalid Ref. This should not happen",
307 __FUNCTION__, static_cast<void *>(
this)
325 if (!lua_isfunction(a_LuaState, a_StackPos))
330 return Super::RefStack(a_LuaState, a_StackPos);
343 if (lua_isnil(a_LuaState, a_StackPos))
350 return Super::RefStack(a_LuaState, a_StackPos);
363 if (!lua_istable(a_LuaState, a_StackPos))
368 return Super::RefStack(a_LuaState, a_StackPos);
380 m_StackPos(a_StackPos)
382 ASSERT(lua_istable(a_LuaState, a_StackPos));
395 for (
int idx = 1; idx <= numElements; idx++)
399 auto shouldAbort = a_ElementCallback(
m_LuaState, idx);
423 auto shouldAbort = a_ElementCallback(
m_LuaState);
491 LOGWARNING(
"%s: Trying to create an already-existing LuaState, ignoring.", __FUNCTION__);
540 LOGWARNING(
"%s: Trying to close an invalid LuaState, ignoring.", __FUNCTION__);
546 "%s: Detected mis-use, calling Close() on an attached state (0x%p). Detaching instead.",
560 m_TrackedRefs.clear();
578 LOGINFO(
"%s: Already contains a LuaState (0x%p), will be closed / detached.", __FUNCTION__, static_cast<void *>(
m_LuaState));
605 "%s: Detected a mis-use, calling Detach() when the state is owned. Closing the owned state (0x%p).",
623 lua_getfield(
m_LuaState, LUA_GLOBALSINDEX,
"package");
624 lua_getfield(
m_LuaState, -1, a_PathVariable.c_str());
626 const char * PackagePath = lua_tolstring(
m_LuaState, -1, &len);
629 AString NewPackagePath(PackagePath, len);
630 NewPackagePath.append(LUA_PATHSEP);
631 NewPackagePath.append(a_Path);
635 lua_pushlstring(
m_LuaState, NewPackagePath.c_str(), NewPackagePath.length());
636 lua_setfield(
m_LuaState, -2, a_PathVariable.c_str());
650 int s = luaL_loadfile(
m_LuaState, a_FileName.c_str());
686 int s = luaL_loadstring(
m_LuaState, a_StringToLoad.c_str());
772 lua_rawgeti(
m_LuaState, LUA_REGISTRYINDEX, static_cast<int>(a_FnRef));
801 lua_rawgeti(
m_LuaState, LUA_REGISTRYINDEX, static_cast<int>(a_TableRef));
832 lua_pushlstring(
m_LuaState, a_String.data(), a_String.size());
843 lua_createtable(
m_LuaState, 0, static_cast<int>(a_Dictionary.size()));
845 for (
const auto & item: a_Dictionary)
861 lua_createtable(
m_LuaState, static_cast<int>(a_Vector.size()), 0);
864 for (AStringVector::const_iterator itr = a_Vector.begin(), end = a_Vector.end(); itr != end; ++itr, ++index)
889 auto c =
new cItem(a_Item);
890 tolua_pushusertype_and_takeownership(
m_LuaState, c,
"cItem");
912 lua_rawgeti(
m_LuaState, LUA_REGISTRYINDEX, static_cast<int>(a_Ref));
923 tolua_pushusertype_and_takeownership(
m_LuaState, c,
"Vector3<double>");
934 tolua_pushusertype_and_takeownership(
m_LuaState, c,
"Vector3<int>");
945 tolua_pushboolean(
m_LuaState, a_Value ? 1 : 0);
956 if (a_Entity ==
nullptr)
962 const char * ClassName = [&]
998 tolua_pushusertype(
m_LuaState, a_Entity, ClassName);
1010 tolua_pushusertype(
m_LuaState, a_ServerHandle,
"cServerHandle");
1021 tolua_pushusertype(
m_LuaState, a_TCPLink,
"cTCPLink");
1032 tolua_pushusertype(
m_LuaState, a_UDPEndpoint,
"cUDPEndpoint");
1065 tolua_pushnumber(
m_LuaState, static_cast<lua_Number>(a_Value));
1087 tolua_pushnumber(
m_LuaState, static_cast<lua_Number>(a_Value.count()));
1108 const char * data = lua_tolstring(
m_LuaState, a_StackPos, &len);
1109 if (data !=
nullptr)
1111 a_Value.assign(data, len);
1129 bool isValid =
true;
1160 bool isValid =
true;
1166 a_Value.push_back(std::move(tempStr));
1185 a_ReturnedVal = (tolua_toboolean(
m_LuaState, a_StackPos, a_ReturnedVal ? 1 : 0) > 0);
1195 return a_Callback.
RefStack(*
this, a_StackPos);
1204 if (a_Callback ==
nullptr)
1206 a_Callback = cpp14::make_unique<cCallback>();
1208 return a_Callback->RefStack(*
this, a_StackPos);
1217 return a_Callback.
RefStack(*
this, a_StackPos);
1226 if (a_Callback ==
nullptr)
1228 a_Callback = cpp14::make_unique<cOptionalCallback>();
1230 return a_Callback->RefStack(*
this, a_StackPos);
1239 if (a_Callback ==
nullptr)
1241 a_Callback = std::make_shared<cCallback>();
1243 return a_Callback->RefStack(*
this, a_StackPos);
1283 a_StackTable = cpp14::make_unique<cStackTable>(*
this, a_StackPos);
1293 return a_TableRef.
RefStack(*
this, a_StackPos);
1302 if (a_TableRef ==
nullptr)
1304 a_TableRef = cpp14::make_unique<cTableRef>();
1306 return a_TableRef->RefStack(*
this, a_StackPos);
1315 return a_Ref.
RefStack(*
this, a_StackPos);
1324 if (a_Ref ==
nullptr)
1326 a_Ref = cpp14::make_unique<cTrackedRef>();
1328 return a_Ref->RefStack(*
this, a_StackPos);
1337 if (a_Ref ==
nullptr)
1339 a_Ref = std::make_shared<cTrackedRef>();
1341 return a_Ref->RefStack(*
this, a_StackPos);
1352 a_ReturnedVal = tolua_tonumber(
m_LuaState, a_StackPos, a_ReturnedVal);
1369 static_cast<int>(tolua_tonumber(
m_LuaState, a_StackPos, a_ReturnedVal)),
1386 static_cast<int>(tolua_tonumber(
m_LuaState, a_StackPos, a_ReturnedVal)),
1400 a_ReturnedVal =
static_cast<float>(tolua_tonumber(
m_LuaState, a_StackPos, a_ReturnedVal));
1417 tolua_Error tolua_Err;
1418 if (tolua_isusertype(
m_LuaState, a_StackPos,
"cUUID", 0, &tolua_Err))
1421 cUUID * PtrUUID =
nullptr;
1423 if (PtrUUID ==
nullptr)
1452 for (
const auto & elem: path)
1484 for (
const auto & elem: path)
1524 int s = lua_pcall(
m_LuaState, NumArgs, a_NumResults, -NumArgs - 2);
1534 LogStackValues(
Printf(
"The Lua stack is in an unexpected state, expected at least two values there, but got %d", top).c_str());
1555 a_EndParam = a_StartParam;
1558 tolua_Error tolua_err;
1559 for (
int i = a_StartParam; i <= a_EndParam; i++)
1561 if (tolua_isusertable(
m_LuaState, i, a_UserTable, 0, &tolua_err))
1569 AString ErrMsg =
Printf(
"#ferror in function '%s'.", (entry.name !=
nullptr) ? entry.name :
"?");
1570 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
1588 a_EndParam = a_StartParam;
1591 tolua_Error tolua_err;
1592 for (
int i = a_StartParam; i <= a_EndParam; i++)
1594 if (tolua_isusertype(
m_LuaState, i, a_UserType, 0, &tolua_err))
1602 AString ErrMsg =
Printf(
"#ferror in function '%s'.", (entry.name !=
nullptr) ? entry.name :
"?");
1603 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
1621 a_EndParam = a_StartParam;
1624 tolua_Error tolua_err;
1625 for (
int i = a_StartParam; i <= a_EndParam; i++)
1627 if (tolua_istable(
m_LuaState, i, 0, &tolua_err))
1635 AString ErrMsg =
Printf(
"#ferror in function '%s'.", (entry.name !=
nullptr) ? entry.name :
"?");
1639 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
1657 a_EndParam = a_StartParam;
1660 tolua_Error tolua_err;
1661 for (
int i = a_StartParam; i <= a_EndParam; i++)
1663 if (tolua_isnumber(
m_LuaState, i, 0, &tolua_err))
1671 AString ErrMsg =
Printf(
"#ferror in function '%s'.", (entry.name !=
nullptr) ? entry.name :
"?");
1672 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
1690 a_EndParam = a_StartParam;
1693 tolua_Error tolua_err;
1694 for (
int i = a_StartParam; i <= a_EndParam; i++)
1696 if (tolua_isboolean(
m_LuaState, i, 0, &tolua_err))
1704 AString ErrMsg =
Printf(
"#ferror in function '%s'.", (entry.name !=
nullptr) ? entry.name :
"?");
1705 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
1723 a_EndParam = a_StartParam;
1726 tolua_Error tolua_err;
1727 for (
int i = a_StartParam; i <= a_EndParam; i++)
1737 tolua_err.array = 0;
1738 tolua_err.type =
"string";
1739 tolua_err.index = i;
1740 AString ErrMsg =
Printf(
"#ferror in function '%s'.", (entry.name !=
nullptr) ? entry.name :
"?");
1741 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
1759 a_EndParam = a_StartParam;
1762 for (
int i = a_StartParam; i <= a_EndParam; i++)
1772 luaL_error(
m_LuaState,
"Error in function '%s' parameter #%d. Function expected, got %s",
1773 (entry.name !=
nullptr) ? entry.name :
"?", i,
GetTypeText(i).c_str()
1792 a_EndParam = a_StartParam;
1795 for (
int i = a_StartParam; i <= a_EndParam; i++)
1805 luaL_error(
m_LuaState,
"Error in function '%s' parameter #%d. Function expected, got %s",
1806 (entry.name !=
nullptr) ? entry.name :
"?", i,
GetTypeText(i).c_str()
1825 a_EndParam = a_StartParam;
1831 for (
int i = a_StartParam; i <= a_EndParam; ++i)
1839 if (!tolua_iscppstring(
m_LuaState, i, 0, &err))
1849 ApiParamError(
"Failed to read parameter #%d. UUID expected, got non-UUID string:\n\t\"%s\"", i, tempStr.c_str());
1862 tolua_Error tolua_err;
1863 if (tolua_isnoobj(
m_LuaState, a_Param, &tolua_err) == 1)
1871 AString ErrMsg =
Printf(
"#ferror in function '%s': Too many arguments.", (entry.name !=
nullptr) ? entry.name :
"?");
1872 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
1882 tolua_Error tolua_err;
1883 if (tolua_isusertype(
m_LuaState, 1, a_SelfClassName, 0, &tolua_err) && !lua_isnil(
m_LuaState, 1))
1893 "Error in function '%s'. The 'self' parameter is not of the expected type, \"instance of %s\". " \
1894 "Make sure you're using the correct calling convention (obj:fn() instead of obj.fn()).",
1895 (entry.name !=
nullptr) ? entry.name :
"<unknown>", a_SelfClassName
1897 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
1907 tolua_Error tolua_err;
1908 if (tolua_isusertable(
m_LuaState, 1, a_SelfClassName, 0, &tolua_err) && !lua_isnil(
m_LuaState, 1))
1918 "Error in function '%s'. The 'self' parameter is not of the expected type, \"class %s\". " \
1919 "Make sure you're using the correct calling convention (cClassName:fn() instead of cClassName.fn() or obj:fn()).",
1920 (entry.name !=
nullptr) ? entry.name :
"<unknown>", a_SelfClassName
1922 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
1934 tolua_Error tolua_err;
1935 return (tolua_isusertype(
m_LuaState, a_Param, a_UserType.c_str(), 0, &tolua_err) == 1);
1946 tolua_Error tolua_err;
1947 return (tolua_isnumber(
m_LuaState, a_Param, 0, &tolua_err) == 1);
1972 lua_pop(a_LuaState, 1);
1993 int depth = a_StartingDepth;
1994 while (lua_getstack(a_LuaState, depth, &entry))
1996 lua_getinfo(a_LuaState,
"Sln", &entry);
1997 LOGWARNING(
" %s(%d): %s", entry.short_src, entry.currentline, entry.name ? entry.name :
"(no name)");
2015 AString errorMsg = fmt::format(
"{0}: {1}", (entry.name !=
nullptr) ? entry.name :
"<unknown function>", a_Msg);
2023 lua_pushstring(
m_LuaState, errorMsg.c_str());
2041 const AString & a_FunctionName,
2043 int a_SrcParamStart,
2056 LOGWARNING(
"Function '%s' not found", a_FunctionName.c_str());
2062 if (
CopyStackFrom(a_SrcLuaState, a_SrcParamStart, a_SrcParamEnd) < 0)
2072 int s = lua_pcall(
m_LuaState, a_SrcParamEnd - a_SrcParamStart + 1, LUA_MULTRET, OldTop + 1);
2111 for (
int i = a_SrcStart; i <= a_SrcEnd; ++i)
2119 return a_SrcEnd - a_SrcStart + 1;
2130 auto srcTop = lua_gettop(a_SrcLuaState);
2134 lua_pushvalue(a_SrcLuaState, a_SrcStackIdx);
2135 lua_pushnil(a_SrcLuaState);
2136 while (lua_next(a_SrcLuaState, -2) != 0)
2138 ASSERT(lua_gettop(a_SrcLuaState) == srcTop + 3);
2145 lua_pop(a_SrcLuaState, 3);
2146 ASSERT(lua_gettop(a_SrcLuaState) == srcTop);
2150 ASSERT(lua_gettop(a_SrcLuaState) == srcTop + 3);
2157 lua_pop(a_SrcLuaState, 3);
2158 ASSERT(lua_gettop(a_SrcLuaState) == srcTop);
2162 ASSERT(lua_gettop(a_SrcLuaState) == srcTop + 3);
2167 lua_pop(a_SrcLuaState, 1);
2168 ASSERT(lua_gettop(a_SrcLuaState) == srcTop + 2);
2171 lua_pop(a_SrcLuaState, 1);
2172 ASSERT(lua_gettop(a_SrcLuaState) == srcTop);
2183 int t = lua_type(a_SrcLuaState, a_StackIdx);
2194 a_SrcLuaState.
ToString(a_StackIdx, s);
2200 bool b = (tolua_toboolean(a_SrcLuaState, a_StackIdx,
false) != 0);
2206 lua_Number d = tolua_tonumber(a_SrcLuaState, a_StackIdx, 0);
2213 const char * type =
nullptr;
2214 if (lua_getmetatable(a_SrcLuaState, a_StackIdx) == 0)
2216 LOGWARNING(
"%s: Unknown class in pos %d, cannot copy.", __FUNCTION__, a_StackIdx);
2219 lua_rawget(a_SrcLuaState, LUA_REGISTRYINDEX);
2221 lua_pop(a_SrcLuaState, 1);
2224 void * ud = tolua_touserdata(a_SrcLuaState, a_StackIdx,
nullptr);
2230 if (!
CopyTableFrom(a_SrcLuaState, a_StackIdx, a_NumAllowedNestingLevels - 1))
2232 LOGWARNING(
"%s: Failed to copy table in pos %d.", __FUNCTION__, a_StackIdx);
2239 LOGWARNING(
"%s: Unsupported value: '%s' at stack position %d. Can only copy numbers, strings, bools, classes and simple tables!",
2240 __FUNCTION__, lua_typename(a_SrcLuaState, t), a_StackIdx
2254 const char * s = lua_tolstring(
m_LuaState, a_StackPos, &len);
2257 a_String.assign(s, len);
2278 LOG(
"%s", (a_Header !=
nullptr) ? a_Header :
"Lua C API Stack contents:");
2279 for (
int i = lua_gettop(a_LuaState); i > 0; i--)
2282 int Type = lua_type(a_LuaState, i);
2285 case LUA_TBOOLEAN: Value.assign((lua_toboolean(a_LuaState, i) != 0) ?
"true" :
"false");
break;
2286 case LUA_TLIGHTUSERDATA:
Printf(Value,
"%p", lua_touserdata(a_LuaState, i));
break;
2287 case LUA_TNUMBER:
Printf(Value,
"%f", static_cast<double>(lua_tonumber(a_LuaState, i)));
break;
2291 const char * txt = lua_tolstring(a_LuaState, i, &len);
2292 Value.assign(txt, std::min<size_t>(len, 50));
2295 case LUA_TTABLE:
Printf(Value,
"%p", lua_topointer(a_LuaState, i));
break;
2296 case LUA_TFUNCTION:
Printf(Value,
"%p", lua_topointer(a_LuaState, i));
break;
2299 Printf(Value,
"%p (%s)", lua_touserdata(a_LuaState, i), tolua_typename(a_LuaState, i));
2301 lua_pop(a_LuaState, 1);
2306 LOGD(
" Idx %d: type %d (%s) %s", i, Type, lua_typename(a_LuaState, Type), Value.c_str());
2325 LOGWARNING(
"%s: Cannot read params: %s, bailing out.", a_FnName, a_ParamNames);
2368 lua_getglobal(a_LuaState,
"BreakIntoDebugger");
2369 if (!lua_isfunction(a_LuaState, -1))
2371 LOGD(
"LUA: BreakIntoDebugger() not found / not a function");
2372 lua_pop(a_LuaState, 1);
2375 lua_pushvalue(a_LuaState, -2);
2376 LOGD(
"Calling BreakIntoDebugger()...");
2377 lua_call(a_LuaState, 1, 0);
2378 LOGD(
"Returned from BreakIntoDebugger().");
2390 if (canonState ==
nullptr)
2392 LOGWARNING(
"%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__, static_cast<void *>(
m_LuaState));
2397 cCSLock Lock(canonState->m_CSTrackedRefs);
2398 canonState->m_TrackedRefs.push_back(&a_Ref);
2409 if (canonState ==
nullptr)
2411 LOGWARNING(
"%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__, static_cast<void *>(
m_LuaState));
2416 cCSLock Lock(canonState->m_CSTrackedRefs);
2417 auto & trackedRefs = canonState->m_TrackedRefs;
2418 for (
auto itr = trackedRefs.begin(), end = trackedRefs.end(); itr != end; ++itr)
2422 trackedRefs.erase(itr);
2460 a_FromRef.m_LuaState =
nullptr;
2461 a_FromRef.m_Ref = LUA_REFNIL;
2489 lua_pushvalue(a_LuaState, a_StackPos);
2490 m_Ref = luaL_ref(a_LuaState, LUA_REGISTRYINDEX);
cTrackedRef(void)
Creates an unbound ref instance.
void LogApiCallParamFailure(const char *a_FnName, const char *a_ParamNames)
Outputs to log a warning about API call being unable to read its parameters from the stack...
bool IsValid(void)
Returns true if the contained reference is valid.
std::atomic< cCriticalSection * > m_CS
The mutex protecting m_Ref against multithreaded access.
bool CheckParamString(int a_StartParam, int a_EndParam=-1)
Returns true if the specified parameters on the stack are strings; also logs warning if not...
A dummy class that's used only to push a constant nil as a function parameter in Call().
std::unique_ptr< cTableRef > cTableRefPtr
int luaopen_lsqlite3(lua_State *L)
bool RefStack(cLuaState &a_LuaState, int a_StackPos)
Set the contained callback to the function in the specified Lua state's stack position.
bool IsSameLuaState(cLuaState &a_LuaState)
Returns true if the reference resides in the specified Lua state.
int m_StackPos
The stack index where the table resides in the Lua state.
bool CallFunction(int a_NumReturnValues)
Pushes a usertype of the specified class type onto the stack.
Represents a table on the Lua stack.
bool CheckParamUserTable(int a_StartParam, const char *a_UserTable, int a_EndParam=-1)
Returns true if the specified parameters on the stack are of the specified usertable type; also logs ...
eEntityType GetEntityType(void) const
void ForEachArrayElement(cFunctionRef< bool(cLuaState &a_LuaState, int a_Index)> a_ElementCallback) const
Iterates over all array elements in the table consecutively and calls the a_ElementCallback for each...
std::shared_ptr< cTrackedRef > cTrackedRefSharedPtr
static AString GetStats(void)
Returns the statistics for all the registered LuaStates.
bool IsLockedByCurrentThread(void)
Returns true if the CS is currently locked by the thread calling this function.
void RefStack(cLuaState &a_LuaState, int a_StackPos)
Creates a reference to Lua object at the specified stack pos, binds this object to it...
void Invalidate(void)
Invalidates the callback, without untracking it from the cLuaState.
Same thing as cCallback, but GetStackValue() won't fail if the callback value is nil.
bool RefStack(cLuaState &a_LuaState, int a_StackPos)
Set the contained reference to the object at the specified Lua state's stack position.
std::vector< cTrackedRef * > m_TrackedRefs
The tracked references.
bool CheckParamStaticSelf(const char *a_SelfClassName)
Returns true if the first parameter is the expected class (static).
bool CopySingleValueFrom(cLuaState &a_SrcLuaState, int a_StackIdx, int a_NumAllowedNestingLevels)
Copies a single value from the specified stack index of the source Lua state to the top of this Lua s...
Represents a stored Lua table with callback functions that C++ code can call.
bool FromString(const AString &a_StringUUID)
Tries to interpret the string as a short or long form UUID and assign from it.
AString m_SubsystemName
The subsystem name is used for reporting errors to the console, it is either "plugin %s" or "LuaScrip...
int luaopen_lxp(lua_State *L)
static void Bind(cLuaState &a_LuaState)
Registers the Json library in the specified Lua state.
bool CheckParamNumber(int a_StartParam, int a_EndParam=-1)
Returns true if the specified parameters on the stack are numbers; also logs warning if not...
Represents a reference to a Lua object that has a tracked lifetime -.
#define lua_tostring(L, i)
bool LoadString(const AString &a_StringToLoad, const AString &a_FileName, bool a_LogWarnings=true)
Loads the specified string.
bool CheckParamSelf(const char *a_SelfClassName)
Returns true if the first parameter is an instance of the expected class name.
bool CheckParamBool(int a_StartParam, int a_EndParam=-1)
Returns true if the specified parameters on the stack are bools; also logs warning if not...
Represents a stored callback to Lua that C++ code can call.
cStackValue WalkToNamedGlobal(const AString &a_Name)
Pushes the named value in the global table to the top of the stack.
void LogStackTrace(int a_StartingDepth=0)
Logs all items in the current stack trace to the server console.
AString m_CurrentFunctionName
Name of the currently pushed function (for the Push / Call chain)
cLuaState(const AString &a_SubsystemName)
Creates a new instance.
bool GetStackValue(int a_StackPos, AString &a_Value)
bool PushFunction(const char *a_FunctionName)
Pushes the function of the specified name onto the stack.
void UnRef(void)
Removes the bound reference, resets the object to Unbound state.
static void Remove(cLuaState &a_LuaState)
Removes the bindings between the specified canon state and its lua_State pointer. ...
Encapsulates a Lua state and provides some syntactic sugar for common operations. ...
bool CheckParamFunctionOrNil(int a_StartParam, int a_EndParam=-1)
Returns true if the specified parameters on the stack are functions or nils; also logs warning if not...
bool m_IsOwned
If true, the state is owned by this object and will be auto-Closed.
bool CheckParamTable(int a_StartParam, int a_EndParam=-1)
Returns true if the specified parameters on the stack are tables; also logs warning if not...
bool CheckParamUserType(int a_StartParam, const char *a_UserType, int a_EndParam=-1)
Returns true if the specified parameters on the stack are of the specified usertype; also logs warnin...
bool CopyTableFrom(cLuaState &a_SrcLuaState, int a_TableIdx, int a_NumAllowedNestingLevels)
Copies a table at the specified stack index of the source Lua state to the top of this Lua state's st...
void TrackCriticalSection(cCriticalSection &a_CS, const AString &a_Name)
Adds the critical section for tracking.
std::vector< AString > AStringVector
Tracks the canon cLuaState instances for each lua_State pointer.
cLuaState * QueryCanonLuaState(void) const
Returns the canon Lua state (the primary cLuaState instance that was used to create, rather than attach, the lua_State structure).
#define ASSERT_LUA_STACK_BALANCE(...)
bool CheckParamEnd(int a_Param)
Returns true if the specified parameter on the stack is nil (indicating an end-of-parameters) ...
void Pop(int a_NumValuesToPop=1)
Pops the specified number of values off the top of the Lua stack.
static cLuaStateTracker & Get(void)
Returns the single instance of this class.
cStackValue WalkToValue(const AString &a_Name)
Pushes the named value in the table at the top of the stack.
std::unique_ptr< cOptionalCallback > cOptionalCallbackPtr
bool IsValid(void) const
Returns true if the reference is valid.
Keeps track of all create cLuaState instances.
void UntrackCriticalSection(cCriticalSection &a_CS)
Removes the CS from the tracking.
void UntrackRef(cTrackedRef &a_Ref)
Removes the specified reference from tracking.
Vector3< double > Vector3d
int m_NumCurrentFunctionArgs
Number of arguments currently pushed (for the Push / Call chain)
bool CheckParamFunction(int a_StartParam, int a_EndParam=-1)
Returns true if the specified parameters on the stack are functions; also logs warning if not...
static int BreakIntoDebugger(lua_State *a_LuaState)
Tries to break into the MobDebug debugger, if it is installed.
std::unique_ptr< cCallback > cCallbackPtr
void LOGINFO(const char *a_Format, fmt::ArgList a_ArgList)
AString & Printf(AString &str, const char *format, fmt::ArgList args)
Output the formatted text into the string.
void Clear(void)
Frees the contained reference, if any.
std::unique_ptr< cStackTable > cStackTablePtr
cCriticalSection m_CS
The mutex protecting m_CanonStates against multithreaded access.
cStackTable(cLuaState &a_LuaState, int a_StackPos)
void ForEachElement(cFunctionRef< bool(cLuaState &a_LuaState)> a_ElementCallback) const
Iterates over all dictionary elements in the table in random order, and calls the a_ElementCallback f...
std::map< lua_State *, cLuaState * > m_CanonStates
Map of lua_State pointers to their canon cLuaState instances.
void Detach(void)
Detaches a previously attached state.
std::map< AString, AString > AStringMap
A string dictionary, used for key-value pairs.
void LOGWARNING(const char *a_Format, fmt::ArgList a_ArgList)
static cLuaState * GetCanonState(lua_State *a_LuaState)
Returns the canon Lua state for the specified lua_State pointer.
void Attach(lua_State *a_State)
Attaches the specified state.
Used for storing references to object in the global registry.
cLuaState & m_LuaState
The Lua state in which the table resides.
static void Del(cLuaState &a_LuaState)
Deletes the specified Lua state from the internal list of LuaStates.
int CallFunctionWithForeignParams(const AString &a_FunctionName, cLuaState &a_SrcLuaState, int a_SrcParamStart, int a_SrcParamEnd)
Calls the function specified by its name, with arguments copied off the foreign state.
void TrackInDeadlockDetect(cDeadlockDetect &a_DeadlockDetect)
Adds this object's CS to the DeadlockDetect's tracked CSs.
void LogStackValues(const char *a_Header=nullptr)
Logs all the elements' types on the API stack, with an optional header for the listing.
T Clamp(T a_Value, T a_Min, T a_Max)
Clamp X to the specified range.
static int ReportFnCallErrors(lua_State *a_LuaState)
Used as the error reporting function for function calls.
A RAII class for values pushed onto the Lua stack.
void Close(void)
Closes the m_LuaState, if not closed already.
eBlockFace
Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc...
cCriticalSection m_CSTrackedRefs
Protects m_TrackedRefs against multithreaded access.
cRef(void)
Creates an unbound reference object.
void AddPackagePath(const AString &a_PathVariable, const AString &a_Path)
Adds the specified path to package.
bool IsParamNumber(int a_Param)
static cCanonLuaStates & GetInstance(void)
Returns the singleton instance of this class.
lua_State * GetLuaState(void)
Returns the Lua state associated with the value.
void Create(void)
Creates the m_LuaState, if not created already.
void LOG(const char *a_Format, fmt::ArgList a_ArgList)
bool HasFunction(const char *a_FunctionName)
Returns true if a_FunctionName is a valid Lua function that can be called.
bool LoadFile(const AString &a_FileName, bool a_LogWarnings=true)
Loads the specified file Returns false and optionally logs a warning to the console if not successful...
AStringVector StringSplit(const AString &str, const AString &delim)
Split the string at any of the listed delimiters.
bool IsParamUserType(int a_Param, AString a_UserType)
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
void RegisterAPILibs(void)
Registers all the API libraries that MCS provides into m_LuaState.
bool IsValid(void) const
Returns true if the m_LuaState is valid.
bool ReportErrors(int status)
If the status is nonzero, prints the text on the top of Lua stack and returns true.
std::unique_ptr< cTrackedRef > cTrackedRefPtr
bool GetStackValues(int a_StartStackPos, Arg1 &&a_Arg1, Args &&...args)
Retrieves a list of values from the Lua stack, starting at the specified index.
int CopyStackFrom(cLuaState &a_SrcLuaState, int a_SrcStart, int a_SrcEnd, int a_NumAllowedNestingLevels=16)
Copies objects on the stack from the specified state.
bool RefStack(cLuaState &a_LuaState, int a_StackPos)
Set the contained reference to the table in the specified Lua state's stack position.
static void Add(cLuaState &a_LuaState)
Adds a new canon cLuaState instance to the map.
virtual const char * GetClass(void) const
Returns the topmost class name for the object.
void Push(Arg1 &&a_Arg1, Arg2 &&a_Arg2, Args &&...a_Args)
Pushes multiple arguments onto the Lua stack.
A dummy class that's used only to delimit function args from return values for cLuaState::Call() ...
std::shared_ptr< cCallback > cCallbackSharedPtr
void TrackRef(cTrackedRef &a_Ref)
Adds the specified reference to tracking.
bool CheckParamUUID(int a_StartParam, int a_EndParam=-1)
Returns true if the specified parameters on the stack are UUIDs; also logs warning if not Accepts eit...
cRef m_Ref
Reference to the Lua callback.
#define UNREACHABLE(x)
Use to mark code that should be impossible to reach.
void UntrackInDeadlockDetect(cDeadlockDetect &a_DeadlockDetect)
Removes this object's CS from the DeadlockDetect's tracked CSs.
AString GetTypeText(int a_StackPos)
Returns the type of the item on the specified position in the stack.
static void Add(cLuaState &a_LuaState)
Adds the specified Lua state to the internal list of LuaStates.
bool RefStack(cLuaState &a_LuaState, int a_StackPos)
Set the contained callback to the function in the specified Lua state's stack position.
int ApiParamError(fmt::StringRef a_Msg)
Prints the message, prefixed with the current function name, then logs the stack contents and raises ...
void ToString(int a_StackPos, AString &a_String)
Reads the value at the specified stack position as a string and sets it to a_String.