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)
71 auto itr = inst.m_CanonStates.find(a_LuaState);
72 if (itr == inst.m_CanonStates.end())
85 ASSERT(inst.m_CanonStates.find(a_LuaState) == inst.m_CanonStates.end());
86 inst.m_CanonStates[a_LuaState.operator lua_State *()] = &a_LuaState;
95 auto itr = inst.m_CanonStates.find(a_LuaState);
96 ASSERT(itr != inst.m_CanonStates.end());
97 inst.m_CanonStates.erase(itr);
112 return canonLuaStates;
125 auto & Instance =
Get();
126 cCSLock Lock(Instance.m_CSLuaStates);
127 Instance.m_LuaStates.push_back(&a_LuaState);
136 auto & Instance =
Get();
137 cCSLock Lock(Instance.m_CSLuaStates);
138 Instance.m_LuaStates.erase(
140 Instance.m_LuaStates.begin(), Instance.m_LuaStates.end(),
143 return (&a_LuaState == a_StoredLuaState);
146 Instance.m_LuaStates.end()
156 auto & Instance =
Get();
157 cCSLock Lock(Instance.m_CSLuaStates);
160 for (
auto state: Instance.m_LuaStates)
165 res.append(fmt::format(FMT_STRING(
"Cannot query memory for state \"{}\"\n"), state->GetSubsystemName()));
169 res.append(fmt::format(FMT_STRING(
"State \"{}\" is using {} KiB of memory\n"), state->GetSubsystemName(), Mem));
173 res.append(fmt::format(FMT_STRING(
"Total memory used by Lua: {} KiB\n"), Total));
213 m_CS = &(canonState->m_CS);
214 m_Ref.RefStack(*canonState, a_StackPos);
225 lua_State * luaState =
nullptr;
227 auto cs =
m_CS.load();
231 if (!m_Ref.IsValid())
235 luaState = m_Ref.GetLuaState();
242 if (luaState ==
nullptr)
255 auto cs =
m_CS.load();
261 return m_Ref.IsValid();
270 auto cs =
m_CS.load();
276 if (!m_Ref.IsValid())
281 if (canonState ==
nullptr)
285 return (m_Ref.GetLuaState() ==
static_cast<lua_State *
>(*canonState));
294 auto cs =
m_CS.load();
301 if (!m_Ref.IsValid())
303 LOGD(
"%s: Inconsistent callback at %p, has a CS but an invalid Ref. This should not happen",
304 __FUNCTION__,
static_cast<void *
>(
this)
322 if (!lua_isfunction(a_LuaState, a_StackPos))
327 return Super::RefStack(a_LuaState, a_StackPos);
340 if (lua_isnil(a_LuaState, a_StackPos))
347 return Super::RefStack(a_LuaState, a_StackPos);
360 if (!lua_istable(a_LuaState, a_StackPos))
365 return Super::RefStack(a_LuaState, a_StackPos);
377 m_StackPos(a_StackPos)
379 ASSERT(lua_istable(a_LuaState, a_StackPos));
388 const auto numElements = luaL_getn(
m_LuaState, m_StackPos);
389 [[maybe_unused]]
const auto stackTop = lua_gettop(
m_LuaState);
390 for (
int idx = 1; idx <= numElements; idx++)
394 auto shouldAbort = a_ElementCallback(
m_LuaState, idx);
411 [[maybe_unused]]
const auto stackTop = lua_gettop(
m_LuaState);
416 auto shouldAbort = a_ElementCallback(
m_LuaState);
450 m_LuaState(a_AttachState),
452 m_SubsystemName(
"<attached>"),
453 m_NumCurrentFunctionArgs(-1)
484 LOGWARNING(
"%s: Trying to create an already-existing LuaState, ignoring.", __FUNCTION__);
533 LOGWARNING(
"%s: Trying to close an invalid LuaState, ignoring.", __FUNCTION__);
539 "%s: Detected mis-use, calling Close() on an attached state (0x%p). Detaching instead.",
571 LOGINFO(
"%s: Already contains a LuaState (0x%p), will be closed / detached.", __FUNCTION__,
static_cast<void *
>(
m_LuaState));
598 "%s: Detected a mis-use, calling Detach() when the state is owned. Closing the owned state (0x%p).",
616 lua_getfield(
m_LuaState, LUA_GLOBALSINDEX,
"package");
617 lua_getfield(
m_LuaState, -1, a_PathVariable.c_str());
619 const char * PackagePath = lua_tolstring(
m_LuaState, -1, &len);
622 AString NewPackagePath(PackagePath, len);
623 NewPackagePath.append(LUA_PATHSEP);
624 NewPackagePath.append(a_Path);
628 lua_pushlstring(
m_LuaState, NewPackagePath.c_str(), NewPackagePath.length());
629 lua_setfield(
m_LuaState, -2, a_PathVariable.c_str());
643 int s = luaL_loadfile(
m_LuaState, a_FileName.c_str());
679 int s = luaL_loadstring(
m_LuaState, a_StringToLoad.c_str());
765 lua_rawgeti(
m_LuaState, LUA_REGISTRYINDEX,
static_cast<int>(a_FnRef));
794 lua_rawgeti(
m_LuaState, LUA_REGISTRYINDEX,
static_cast<int>(a_TableRef));
825 lua_pushlstring(
m_LuaState, a_String.data(), a_String.size());
836 lua_createtable(
m_LuaState, 0,
static_cast<int>(a_Dictionary.size()));
838 for (
const auto & item: a_Dictionary)
854 lua_createtable(
m_LuaState,
static_cast<int>(a_Vector.size()), 0);
857 for (AStringVector::const_iterator itr = a_Vector.begin(), end = a_Vector.end(); itr != end; ++itr, ++index)
882 auto c =
new cItem(a_Item);
883 tolua_pushusertype_and_takeownership(
m_LuaState, c,
"cItem");
905 lua_rawgeti(
m_LuaState, LUA_REGISTRYINDEX,
static_cast<int>(a_Ref));
916 lua_pushlstring(
m_LuaState,
reinterpret_cast<const char *
>(a_Data.data()), a_Data.size());
927 tolua_pushusertype_and_takeownership(
m_LuaState, c,
"Vector3<double>");
938 tolua_pushusertype_and_takeownership(
m_LuaState, c,
"Vector3<int>");
949 tolua_pushboolean(
m_LuaState, a_Value ? 1 : 0);
970 if (a_Entity ==
nullptr)
976 const char * ClassName = [&]
1012 tolua_pushusertype(
m_LuaState, a_Entity, ClassName);
1024 tolua_pushusertype(
m_LuaState, a_ServerHandle,
"cServerHandle");
1035 tolua_pushusertype(
m_LuaState, a_TCPLink,
"cTCPLink");
1046 tolua_pushusertype(
m_LuaState, a_UDPEndpoint,
"cUDPEndpoint");
1079 tolua_pushnumber(
m_LuaState,
static_cast<lua_Number
>(a_Value));
1101 tolua_pushnumber(
m_LuaState,
static_cast<lua_Number
>(a_Value.count()));
1122 const char * data = lua_tolstring(
m_LuaState, a_StackPos, &len);
1123 if (data !=
nullptr)
1125 a_Value.assign(data, len);
1143 bool isValid =
true;
1174 bool isValid =
true;
1180 a_Value.push_back(std::move(tempStr));
1199 a_ReturnedVal = (tolua_toboolean(
m_LuaState, a_StackPos, a_ReturnedVal ? 1 : 0) > 0);
1209 return a_Callback.
RefStack(*
this, a_StackPos);
1218 if (a_Callback ==
nullptr)
1220 a_Callback = std::make_unique<cCallback>();
1222 return a_Callback->RefStack(*
this, a_StackPos);
1231 return a_Callback.
RefStack(*
this, a_StackPos);
1240 if (a_Callback ==
nullptr)
1242 a_Callback = std::make_unique<cOptionalCallback>();
1244 return a_Callback->RefStack(*
this, a_StackPos);
1253 if (a_Callback ==
nullptr)
1255 a_Callback = std::make_shared<cCallback>();
1257 return a_Callback->RefStack(*
this, a_StackPos);
1297 a_StackTable = std::make_unique<cStackTable>(*
this, a_StackPos);
1307 return a_TableRef.
RefStack(*
this, a_StackPos);
1316 if (a_TableRef ==
nullptr)
1318 a_TableRef = std::make_unique<cTableRef>();
1320 return a_TableRef->RefStack(*
this, a_StackPos);
1329 return a_Ref.
RefStack(*
this, a_StackPos);
1338 if (a_Ref ==
nullptr)
1340 a_Ref = std::make_unique<cTrackedRef>();
1342 return a_Ref->RefStack(*
this, a_StackPos);
1351 if (a_Ref ==
nullptr)
1353 a_Ref = std::make_shared<cTrackedRef>();
1355 return a_Ref->RefStack(*
this, a_StackPos);
1365 const char *
const Data = lua_tolstring(
m_LuaState, a_StackPos, &Length);
1366 if (Data !=
nullptr)
1368 a_Data.assign(
reinterpret_cast<const std::byte *
>(Data), Length);
1382 a_Value =
static_cast<CustomStatistic>(
static_cast<std::underlying_type_t<CustomStatistic>
>(lua_tonumber(
m_LuaState, a_StackPos)));
1397 a_ReturnedVal = tolua_tonumber(
m_LuaState, a_StackPos, a_ReturnedVal);
1414 static_cast<int>(tolua_tonumber(
m_LuaState, a_StackPos, a_ReturnedVal)),
1431 static_cast<int>(tolua_tonumber(
m_LuaState, a_StackPos, a_ReturnedVal)),
1445 a_ReturnedVal =
static_cast<float>(tolua_tonumber(
m_LuaState, a_StackPos, a_ReturnedVal));
1462 tolua_Error tolua_Err;
1463 if (tolua_isusertype(
m_LuaState, a_StackPos,
"cUUID", 0, &tolua_Err))
1466 cUUID * PtrUUID =
nullptr;
1468 if (PtrUUID ==
nullptr)
1492 const char *
const Value = lua_tolstring(
m_LuaState, a_StackPos, &Length);
1493 if (Value !=
nullptr)
1495 a_Value = { Value, Length };
1505 template <
typename T>
1513 if (tolua_isusertype(
m_LuaState, a_StackPos,
"Vector3<double>", 0, &err))
1515 a_ReturnedVal = **(
static_cast<const Vector3d **
>(lua_touserdata(
m_LuaState, a_StackPos)));
1518 if (tolua_isusertype(
m_LuaState, a_StackPos,
"Vector3<float>", 0, &err))
1520 a_ReturnedVal = **(
static_cast<const Vector3f **
>(lua_touserdata(
m_LuaState, a_StackPos)));
1523 if (tolua_isusertype(
m_LuaState, a_StackPos,
"Vector3<int>", 0, &err))
1525 a_ReturnedVal = **(
static_cast<const Vector3i **
>(lua_touserdata(
m_LuaState, a_StackPos)));
1564 for (
const auto & elem: path)
1596 for (
const auto & elem: path)
1636 int s = lua_pcall(
m_LuaState, NumArgs, a_NumResults, -NumArgs - 2);
1646 LogStackValues(fmt::format(FMT_STRING(
"The Lua stack is in an unexpected state, expected at least two values there, but got {}"), top).c_str());
1667 a_EndParam = a_StartParam;
1670 tolua_Error tolua_err;
1671 for (
int i = a_StartParam; i <= a_EndParam; i++)
1673 if (tolua_isusertable(
m_LuaState, i, a_UserTable, 0, &tolua_err))
1681 AString ErrMsg = fmt::format(FMT_STRING(
"#ferror in function '{}'."), (entry.name !=
nullptr) ? entry.name :
"?");
1682 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
1700 a_EndParam = a_StartParam;
1703 tolua_Error tolua_err;
1704 for (
int i = a_StartParam; i <= a_EndParam; i++)
1706 if (tolua_isusertype(
m_LuaState, i, a_UserType, 0, &tolua_err))
1714 AString ErrMsg = fmt::format(FMT_STRING(
"#ferror in function '{}'."), (entry.name !=
nullptr) ? entry.name :
"?");
1715 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
1733 a_EndParam = a_StartParam;
1736 tolua_Error tolua_err;
1737 for (
int i = a_StartParam; i <= a_EndParam; i++)
1739 if (tolua_istable(
m_LuaState, i, 0, &tolua_err))
1747 AString ErrMsg = fmt::format(FMT_STRING(
"#ferror in function '{}'."), (entry.name !=
nullptr) ? entry.name :
"?");
1751 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
1769 a_EndParam = a_StartParam;
1772 tolua_Error tolua_err;
1773 for (
int i = a_StartParam; i <= a_EndParam; i++)
1775 if (tolua_isnumber(
m_LuaState, i, 0, &tolua_err))
1783 AString ErrMsg = fmt::format(FMT_STRING(
"#ferror in function '{}'."), (entry.name !=
nullptr) ? entry.name :
"?");
1784 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
1802 a_EndParam = a_StartParam;
1805 tolua_Error tolua_err;
1806 for (
int i = a_StartParam; i <= a_EndParam; i++)
1808 if (tolua_isboolean(
m_LuaState, i, 0, &tolua_err))
1816 AString ErrMsg = fmt::format(FMT_STRING(
"#ferror in function '{}'."), (entry.name !=
nullptr) ? entry.name :
"?");
1817 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
1835 a_EndParam = a_StartParam;
1838 tolua_Error tolua_err;
1839 for (
int i = a_StartParam; i <= a_EndParam; i++)
1849 tolua_err.array = 0;
1850 tolua_err.type =
"string";
1851 tolua_err.index = i;
1852 AString ErrMsg = fmt::format(FMT_STRING(
"#ferror in function '{}'."), (entry.name !=
nullptr) ? entry.name :
"?");
1853 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
1871 a_EndParam = a_StartParam;
1874 for (
int i = a_StartParam; i <= a_EndParam; i++)
1884 luaL_error(
m_LuaState,
"Error in function '%s' parameter #%d. Function expected, got %s",
1885 (entry.name !=
nullptr) ? entry.name :
"?", i,
GetTypeText(i).c_str()
1904 a_EndParam = a_StartParam;
1907 for (
int i = a_StartParam; i <= a_EndParam; i++)
1917 luaL_error(
m_LuaState,
"Error in function '%s' parameter #%d. Function expected, got %s",
1918 (entry.name !=
nullptr) ? entry.name :
"?", i,
GetTypeText(i).c_str()
1937 a_EndParam = a_StartParam;
1940 for (
int i = a_StartParam; i <= a_EndParam; ++i)
1947 ApiParamError(fmt::format(FMT_STRING(
"Failed to read parameter #{}. Vector3 expected, got {}"), i,
GetTypeText(i)));
1963 a_EndParam = a_StartParam;
1969 for (
int i = a_StartParam; i <= a_EndParam; ++i)
1977 if (!tolua_iscppstring(
m_LuaState, i, 0, &err))
1987 ApiParamError(fmt::format(FMT_STRING(
"Failed to read parameter #{}. UUID expected, got non-UUID string:\n\t\"{}\""), i, tempStr));
2000 tolua_Error tolua_err;
2001 if (tolua_isnoobj(
m_LuaState, a_Param, &tolua_err) == 1)
2009 AString ErrMsg = fmt::format(FMT_STRING(
"#ferror in function '{}': Too many arguments."), (entry.name !=
nullptr) ? entry.name :
"?");
2010 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
2020 tolua_Error tolua_err;
2021 if (tolua_isusertype(
m_LuaState, 1, a_SelfClassName, 0, &tolua_err) && !lua_isnil(
m_LuaState, 1))
2031 FMT_STRING(
"Error in function '{}'. The 'self' parameter is not of the expected type, \"instance of {}\". " \
2032 "Make sure you're using the correct calling convention (obj:fn() instead of obj.fn())."),
2033 (entry.name !=
nullptr) ? entry.name :
"<unknown>", a_SelfClassName
2035 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
2045 tolua_Error tolua_err;
2046 if (tolua_isusertable(
m_LuaState, 1, a_SelfClassName, 0, &tolua_err) && !lua_isnil(
m_LuaState, 1))
2056 FMT_STRING(
"Error in function '{}'. The 'self' parameter is not of the expected type, \"class {}\". " \
2057 "Make sure you're using the correct calling convention (cClassName:fn() instead of cClassName.fn() or obj:fn())."),
2058 (entry.name !=
nullptr) ? entry.name :
"<unknown>", a_SelfClassName
2060 tolua_error(
m_LuaState, ErrMsg.c_str(), &tolua_err);
2072 tolua_Error tolua_err;
2073 return (tolua_isusertype(
m_LuaState, a_ParamIdx, a_UserType.c_str(), 0, &tolua_err) == 1);
2084 tolua_Error tolua_err;
2085 return (tolua_isnumber(
m_LuaState, a_ParamIdx, 0, &tolua_err) == 1);
2126 lua_pop(a_LuaState, 1);
2147 int depth = a_StartingDepth;
2148 while (lua_getstack(a_LuaState, depth, &entry))
2150 lua_getinfo(a_LuaState,
"Sln", &entry);
2151 LOGWARNING(
" %s(%d): %s", entry.short_src, entry.currentline, entry.name ? entry.name :
"(no name)");
2169 AString errorMsg = fmt::format(
"{0}: {1}", (entry.name !=
nullptr) ? entry.name :
"<unknown function>", a_Msg);
2177 lua_pushstring(
m_LuaState, errorMsg.c_str());
2195 const AString & a_FunctionName,
2197 int a_SrcParamStart,
2210 LOGWARNING(
"Function '%s' not found", a_FunctionName.c_str());
2216 if (
CopyStackFrom(a_SrcLuaState, a_SrcParamStart, a_SrcParamEnd) < 0)
2226 int s = lua_pcall(
m_LuaState, a_SrcParamEnd - a_SrcParamStart + 1, LUA_MULTRET, OldTop + 1);
2265 for (
int i = a_SrcStart; i <= a_SrcEnd; ++i)
2273 return a_SrcEnd - a_SrcStart + 1;
2282 [[maybe_unused]]
const auto srcTop = lua_gettop(a_SrcLuaState);
2283 [[maybe_unused]]
const auto dstTop = lua_gettop(
m_LuaState);
2287 lua_pushvalue(a_SrcLuaState, a_SrcStackIdx);
2288 lua_pushnil(a_SrcLuaState);
2289 while (lua_next(a_SrcLuaState, -2) != 0)
2291 ASSERT(lua_gettop(a_SrcLuaState) == srcTop + 3);
2298 lua_pop(a_SrcLuaState, 3);
2299 ASSERT(lua_gettop(a_SrcLuaState) == srcTop);
2303 ASSERT(lua_gettop(a_SrcLuaState) == srcTop + 3);
2310 lua_pop(a_SrcLuaState, 3);
2311 ASSERT(lua_gettop(a_SrcLuaState) == srcTop);
2315 ASSERT(lua_gettop(a_SrcLuaState) == srcTop + 3);
2320 lua_pop(a_SrcLuaState, 1);
2321 ASSERT(lua_gettop(a_SrcLuaState) == srcTop + 2);
2324 lua_pop(a_SrcLuaState, 1);
2325 ASSERT(lua_gettop(a_SrcLuaState) == srcTop);
2336 int t = lua_type(a_SrcLuaState, a_StackIdx);
2347 a_SrcLuaState.
ToString(a_StackIdx, s);
2353 bool b = (tolua_toboolean(a_SrcLuaState, a_StackIdx,
false) != 0);
2359 lua_Number d = tolua_tonumber(a_SrcLuaState, a_StackIdx, 0);
2366 const char * type =
nullptr;
2367 if (lua_getmetatable(a_SrcLuaState, a_StackIdx) == 0)
2369 LOGWARNING(
"%s: Unknown class in pos %d, cannot copy.", __FUNCTION__, a_StackIdx);
2372 lua_rawget(a_SrcLuaState, LUA_REGISTRYINDEX);
2374 lua_pop(a_SrcLuaState, 1);
2377 void * ud = tolua_touserdata(a_SrcLuaState, a_StackIdx,
nullptr);
2383 if (!
CopyTableFrom(a_SrcLuaState, a_StackIdx, a_NumAllowedNestingLevels - 1))
2385 LOGWARNING(
"%s: Failed to copy table in pos %d.", __FUNCTION__, a_StackIdx);
2392 LOGWARNING(
"%s: Unsupported value: '%s' at stack position %d. Can only copy numbers, strings, bools, classes and simple tables!",
2393 __FUNCTION__, lua_typename(a_SrcLuaState, t), a_StackIdx
2407 const char * s = lua_tolstring(
m_LuaState, a_StackPos, &len);
2410 a_String.assign(s, len);
2431 LOG(
"%s", (a_Header !=
nullptr) ? a_Header :
"Lua C API Stack contents:");
2432 for (
int i = lua_gettop(a_LuaState); i > 0; i--)
2435 int Type = lua_type(a_LuaState, i);
2438 case LUA_TBOOLEAN: Value.assign((lua_toboolean(a_LuaState, i) != 0) ?
"true" :
"false");
break;
2439 case LUA_TLIGHTUSERDATA: Value = fmt::format(FMT_STRING(
"{}"), lua_touserdata(a_LuaState, i));
break;
2440 case LUA_TNUMBER: Value = fmt::format(FMT_STRING(
"{}"), lua_tonumber(a_LuaState, i));
break;
2444 const char * txt = lua_tolstring(a_LuaState, i, &len);
2445 Value.assign(txt, std::min<size_t>(len, 50));
2448 case LUA_TTABLE: Value = fmt::format(FMT_STRING(
"{}"), lua_topointer(a_LuaState, i));
break;
2449 case LUA_TFUNCTION: Value = fmt::format(FMT_STRING(
"{}"), lua_topointer(a_LuaState, i));
break;
2452 Value = fmt::format(FMT_STRING(
"{} ({})"), lua_touserdata(a_LuaState, i), tolua_typename(a_LuaState, i));
2454 lua_pop(a_LuaState, 1);
2459 LOGD(
" Idx %d: type %d (%s) %s", i,
Type, lua_typename(a_LuaState,
Type), Value.c_str());
2478 LOGWARNING(
"%s: Cannot read params: %s, bailing out.", a_FnName, a_ParamNames);
2521 lua_getglobal(a_LuaState,
"BreakIntoDebugger");
2522 if (!lua_isfunction(a_LuaState, -1))
2524 LOGD(
"LUA: BreakIntoDebugger() not found / not a function");
2525 lua_pop(a_LuaState, 1);
2528 lua_pushvalue(a_LuaState, -2);
2529 LOGD(
"Calling BreakIntoDebugger()...");
2530 lua_call(a_LuaState, 1, 0);
2531 LOGD(
"Returned from BreakIntoDebugger().");
2543 if (canonState ==
nullptr)
2545 LOGWARNING(
"%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__,
static_cast<void *
>(
m_LuaState));
2550 cCSLock Lock(canonState->m_CSTrackedRefs);
2551 canonState->m_TrackedRefs.push_back(&a_Ref);
2562 if (canonState ==
nullptr)
2564 LOGWARNING(
"%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__,
static_cast<void *
>(
m_LuaState));
2569 cCSLock Lock(canonState->m_CSTrackedRefs);
2570 auto & trackedRefs = canonState->m_TrackedRefs;
2571 for (
auto itr = trackedRefs.begin(), end = trackedRefs.end(); itr != end; ++itr)
2575 trackedRefs.erase(itr);
2589 m_LuaState(nullptr),
2611 m_Ref(a_FromRef.m_Ref)
2613 a_FromRef.m_LuaState =
nullptr;
2614 a_FromRef.m_Ref = LUA_REFNIL;
2642 lua_pushvalue(a_LuaState, a_StackPos);
2643 m_Ref = luaL_ref(a_LuaState, LUA_REGISTRYINDEX);
2655 luaL_unref(
m_LuaState, LUA_REGISTRYINDEX, m_Ref);
int luaopen_lsqlite3(lua_State *L)
int luaopen_lxp(lua_State *L)
#define lua_tostring(L, i)
#define ASSERT_LUA_STACK_BALANCE(...)
eBlockFace
Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc.
std::basic_string_view< std::byte > ContiguousByteBufferView
T Clamp(T a_Value, T a_Min, T a_Max)
Clamp X to the specified range.
std::basic_string< std::byte > ContiguousByteBuffer
void LOGWARNING(std::string_view a_Format, const Args &... args)
void LOG(std::string_view a_Format, const Args &... args)
void LOGINFO(std::string_view a_Format, const Args &... args)
AStringVector StringSplit(const AString &str, const AString &delim)
Split the string at any of the listed delimiters.
std::vector< AString > AStringVector
std::map< AString, AString > AStringMap
A string dictionary, used for key-value pairs.
Vector3< double > Vector3d
static void Bind(cLuaState &a_LuaState)
Registers the Json library in the specified Lua state.
Tracks the canon cLuaState instances for each lua_State pointer.
std::map< lua_State *, cLuaState * > m_CanonStates
Map of lua_State pointers to their canon cLuaState instances.
static cCanonLuaStates & GetInstance(void)
Returns the singleton instance of this class.
cCriticalSection m_CS
The mutex protecting m_CanonStates against multithreaded access.
static cLuaState * GetCanonState(lua_State *a_LuaState)
Returns the canon Lua state for the specified lua_State pointer.
static void Add(cLuaState &a_LuaState)
Adds a new canon cLuaState instance to the map.
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.
void TrackRef(cTrackedRef &a_Ref)
Adds the specified reference to tracking.
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...
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.
bool PushFunction(const char *a_FunctionName)
Pushes the function of the specified name onto the stack.
void AddPackagePath(const AString &a_PathVariable, const AString &a_Path)
Adds the specified path to package.
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 CheckParamVector3(int a_StartParam, int a_EndParam=-1)
Returns true if the specified parameters on the stack are Vector3s; also logs warning if not.
std::vector< cTrackedRef * > m_TrackedRefs
The tracked references.
void Push(Arg1 &&a_Arg1, Arg2 &&a_Arg2, Args &&... a_Args)
Pushes multiple arguments onto the Lua stack.
void LogStackValues(const char *a_Header=nullptr)
Logs all the elements' types on the API stack, with an optional header for the listing.
cLuaState(const AString &a_SubsystemName)
Creates a new instance.
void LogStackTrace(int a_StartingDepth=0)
Logs all items in the current stack trace to the server console.
std::unique_ptr< cOptionalCallback > cOptionalCallbackPtr
std::unique_ptr< cCallback > cCallbackPtr
bool ReportErrors(int status)
If the status is nonzero, prints the text on the top of Lua stack and returns true.
bool CheckParamEnd(int a_Param)
Returns true if the specified parameter on the stack is nil (indicating an end-of-parameters)
cLuaState * QueryCanonLuaState(void) const
Returns the canon Lua state (the primary cLuaState instance that was used to create,...
bool IsParamUserType(int a_ParamIdx, const AString &a_UserType)
Returns true if the specified parameter is of the specified class.
bool CallFunction(int a_NumReturnValues)
Pushes a usertype of the specified class type onto the stack.
std::unique_ptr< cStackTable > cStackTablePtr
bool IsParamVector3(int a_ParamIdx)
Returns true if the specified parameter is any of the Vector3 types.
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.
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.
AString m_SubsystemName
The subsystem name is used for reporting errors to the console, it is either "plugin %s" or "LuaScrip...
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.
void Close(void)
Closes the m_LuaState, if not closed already.
void UntrackRef(cTrackedRef &a_Ref)
Removes the specified reference from tracking.
static int BreakIntoDebugger(lua_State *a_LuaState)
Tries to break into the MobDebug debugger, if it is installed.
int m_NumCurrentFunctionArgs
Number of arguments currently pushed (for the Push / Call chain)
bool CheckParamSelf(const char *a_SelfClassName)
Returns true if the first parameter is an instance of the expected class name.
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...
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...
std::unique_ptr< cTrackedRef > cTrackedRefPtr
bool m_IsOwned
If true, the state is owned by this object and will be auto-Closed.
void RegisterAPILibs(void)
Registers all the API libraries that MCS provides into m_LuaState.
int CopyStackFrom(cLuaState &a_SrcLuaState, int a_SrcStart, int a_SrcEnd, int a_NumAllowedNestingLevels=16)
Copies objects on the stack from the specified state.
std::unique_ptr< cTableRef > cTableRefPtr
cStackValue WalkToNamedGlobal(const AString &a_Name)
Pushes the named value in the global table to the top of the stack.
bool IsValid(void) const
Returns true if the m_LuaState is valid.
std::shared_ptr< cTrackedRef > cTrackedRefSharedPtr
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.
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 ...
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,...
static int ReportFnCallErrors(lua_State *a_LuaState)
Used as the error reporting function for function calls.
AString m_CurrentFunctionName
Name of the currently pushed function (for the Push / Call chain)
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...
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.
cCriticalSection m_CSTrackedRefs
Protects m_TrackedRefs against multithreaded access.
AString GetTypeText(int a_StackPos)
Returns the type of the item on the specified position in the stack.
void UntrackInDeadlockDetect(cDeadlockDetect &a_DeadlockDetect)
Removes this object's CS from the DeadlockDetect's tracked CSs.
void Pop(int a_NumValuesToPop=1)
Pops the specified number of values off the top of the Lua stack.
cStackValue WalkToValue(const AString &a_Name)
Pushes the named value in the table at the top of the stack.
bool LoadString(const AString &a_StringToLoad, const AString &a_FileName, bool a_LogWarnings=true)
Loads the specified string.
void Detach(void)
Detaches a previously attached state.
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 CheckParamStaticSelf(const char *a_SelfClassName)
Returns true if the first parameter is the expected class (static).
bool GetStackValue(int a_StackPos, AString &a_Value)
int ApiParamError(std::string_view a_Msg)
Prints the message, prefixed with the current function name, then logs the stack contents and raises ...
void Attach(lua_State *a_State)
Attaches the specified state.
bool GetStackValues(int a_StartStackPos, Arg1 &&a_Arg1, Args &&... args)
Retrieves a list of values from the Lua stack, starting at the specified index.
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...
void TrackInDeadlockDetect(cDeadlockDetect &a_DeadlockDetect)
Adds this object's CS to the DeadlockDetect's tracked CSs.
std::shared_ptr< cCallback > cCallbackSharedPtr
void Create(void)
Creates the m_LuaState, if not created already.
bool IsParamNumber(int a_ParamIdx)
Returns true if the specified parameter is a number.
Used for storing references to object in the global registry.
cRef(void)
Creates an unbound reference object.
void UnRef(void)
Removes the bound reference, resets the object to Unbound state.
bool IsValid(void) const
Returns true if the reference is valid.
void RefStack(cLuaState &a_LuaState, int a_StackPos)
Creates a reference to Lua object at the specified stack pos, binds this object to it.
Represents a reference to a Lua object that has a tracked lifetime -.
bool IsSameLuaState(cLuaState &a_LuaState)
Returns true if the reference resides in the specified Lua state.
cTrackedRef(void)
Creates an unbound ref instance.
bool IsValid(void)
Returns true if the contained reference is valid.
void Clear(void)
Frees the contained reference, if any.
bool RefStack(cLuaState &a_LuaState, int a_StackPos)
Set the contained reference to the object at the specified Lua state's stack position.
void Invalidate(void)
Invalidates the callback, without untracking it from the cLuaState.
Represents a stored callback to Lua that C++ code can call.
bool RefStack(cLuaState &a_LuaState, int a_StackPos)
Set the contained callback to the function in the specified Lua state's stack position.
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 callback to the function in the specified Lua state's stack position.
Represents a stored Lua table with callback functions that C++ code can call.
bool RefStack(cLuaState &a_LuaState, int a_StackPos)
Set the contained reference to the table in the specified Lua state's stack position.
A dummy class that's used only to delimit function args from return values for cLuaState::Call()
A dummy class that's used only to push a constant nil as a function parameter in Call().
A RAII class for values pushed onto the Lua stack.
Represents a table on the Lua stack.
cStackTable(cLuaState &a_LuaState, int a_StackPos)
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.
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...
Keeps track of all create cLuaState instances.
static AString GetStats(void)
Returns the statistics for all the registered LuaStates.
static void Add(cLuaState &a_LuaState)
Adds the specified Lua state to the internal list of LuaStates.
static void Del(cLuaState &a_LuaState)
Deletes the specified Lua state from the internal list of LuaStates.
static cLuaStateTracker & Get(void)
Returns the single instance of this class.
void UntrackCriticalSection(cCriticalSection &a_CS)
Removes the CS from the tracking.
void TrackCriticalSection(cCriticalSection &a_CS, const AString &a_Name)
Adds the critical section for tracking.
virtual const char * GetClass(void) const
Returns the topmost class name for the object.
eEntityType GetEntityType(void) const
bool IsLockedByCurrentThread(void)
Returns true if the CS is currently locked by the thread calling this function.
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
bool FromString(const AString &a_StringUUID)
Tries to interpret the string as a short or long form UUID and assign from it.