1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

Implement helpful __tostring for all userdata-based classes

This commit is contained in:
Lars Mueller 2025-04-27 17:27:55 +02:00 committed by Lars Müller
parent 9ad23e4384
commit 747857bffa
22 changed files with 103 additions and 66 deletions

View file

@ -330,7 +330,7 @@ void LuaAreaStore::Register(lua_State *L)
{"__gc", gc_object},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<LuaAreaStore>(L, methods, metamethods);
// Can be created from Lua (AreaStore())
lua_register(L, className, create_object);

View file

@ -90,29 +90,6 @@ bool ModApiBase::registerFunction(lua_State *L, const char *name,
return true;
}
void ModApiBase::registerClass(lua_State *L, const char *name,
const luaL_Reg *methods,
const luaL_Reg *metamethods)
{
luaL_newmetatable(L, name);
luaL_register(L, NULL, metamethods);
int metatable = lua_gettop(L);
lua_newtable(L);
luaL_register(L, NULL, methods);
int methodtable = lua_gettop(L);
lua_pushvalue(L, methodtable);
lua_setfield(L, metatable, "__index");
// Protect the real metatable.
lua_pushvalue(L, methodtable);
lua_setfield(L, metatable, "__metatable");
// Pop methodtable and metatable.
lua_pop(L, 2);
}
int ModApiBase::l_deprecated_function(lua_State *L, const char *good, const char *bad, lua_CFunction func)
{
thread_local std::vector<u64> deprecated_logged;

View file

@ -60,9 +60,37 @@ public:
lua_CFunction func,
int top);
static void registerClass(lua_State *L, const char *name,
template<typename T>
static void registerClass(lua_State *L,
const luaL_Reg *methods,
const luaL_Reg *metamethods);
const luaL_Reg *metamethods)
{
luaL_newmetatable(L, T::className);
luaL_register(L, NULL, metamethods);
int metatable = lua_gettop(L);
lua_newtable(L);
luaL_register(L, NULL, methods);
int methodtable = lua_gettop(L);
lua_pushvalue(L, methodtable);
lua_setfield(L, metatable, "__index");
lua_getfield(L, metatable, "__tostring");
bool default_tostring = lua_isnil(L, -1);
lua_pop(L, 1);
if (default_tostring) {
lua_pushcfunction(L, ModApiBase::defaultToString<T>);
lua_setfield(L, metatable, "__tostring");
}
// Protect the real metatable.
lua_pushvalue(L, methodtable);
lua_setfield(L, metatable, "__metatable");
// Pop methodtable and metatable.
lua_pop(L, 2);
}
template<typename T>
static inline T *checkObject(lua_State *L, int narg)
@ -84,4 +112,14 @@ public:
* @return value from `func`
*/
static int l_deprecated_function(lua_State *L, const char *good, const char *bad, lua_CFunction func);
private:
template<typename T>
static int defaultToString(lua_State *L)
{
auto *t = checkObject<T>(L, 1);
lua_pushfstring(L, "%s: %p", T::className, t);
return 1;
}
};

View file

@ -175,7 +175,7 @@ void LuaCamera::Register(lua_State *L)
{"__gc", gc_object},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<LuaCamera>(L, methods, metamethods);
}
const char LuaCamera::className[] = "Camera";

View file

@ -124,7 +124,7 @@ void LuaRaycast::Register(lua_State *L)
{"__gc", gc_object},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<LuaRaycast>(L, methods, metamethods);
lua_register(L, className, create_object);
}

View file

@ -410,7 +410,7 @@ void InvRef::Register(lua_State *L)
{"__gc", gc_object},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<InvRef>(L, methods, metamethods);
// Cannot be created from Lua
//lua_register(L, className, create_object);

View file

@ -524,7 +524,7 @@ void LuaItemStack::Register(lua_State *L)
{"__eq", l_equals},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<LuaItemStack>(L, methods, metamethods);
// Can be created from Lua (ItemStack(itemstack or itemstring or table or nil))
lua_register(L, className, create_object);

View file

@ -81,7 +81,7 @@ void ItemStackMetaRef::create(lua_State *L, LuaItemStack *istack)
void ItemStackMetaRef::Register(lua_State *L)
{
registerMetadataClass(L, className, methods);
registerMetadataClass<ItemStackMetaRef>(L, methods);
}
const char ItemStackMetaRef::className[] = "ItemStackMetaRef";

View file

@ -464,7 +464,7 @@ void LuaLocalPlayer::Register(lua_State *L)
{"__gc", gc_object},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<LuaLocalPlayer>(L, methods, metamethods);
}
const char LuaLocalPlayer::className[] = "LocalPlayer";

View file

@ -315,20 +315,3 @@ int MetaDataRef::l_equals(lua_State *L)
lua_pushboolean(L, *data1 == *data2);
return 1;
}
void MetaDataRef::registerMetadataClass(lua_State *L, const char *name,
const luaL_Reg *methods)
{
const luaL_Reg metamethods[] = {
{"__eq", l_equals},
{"__gc", gc_object},
{0, 0}
};
registerClass(L, name, methods, metamethods);
// Set metadata_class in the metatable for MetaDataRef::checkAnyMetadata.
luaL_getmetatable(L, name);
lua_pushstring(L, name);
lua_setfield(L, -2, "metadata_class");
lua_pop(L, 1);
}

View file

@ -29,7 +29,22 @@ protected:
virtual void handleToTable(lua_State *L, IMetadata *meta);
virtual bool handleFromTable(lua_State *L, int table, IMetadata *meta);
static void registerMetadataClass(lua_State *L, const char *name, const luaL_Reg *methods);
template<class T>
static void registerMetadataClass(lua_State *L, const luaL_Reg *methods)
{
const luaL_Reg metamethods[] = {
{"__eq", l_equals},
{"__gc", gc_object},
{0, 0}
};
registerClass<T>(L, methods, metamethods);
// Set metadata_class in the metatable for MetaDataRef::checkAnyMetadata.
luaL_getmetatable(L, T::className);
lua_pushstring(L, T::className);
lua_setfield(L, -2, "metadata_class");
lua_pop(L, 1);
}
// Exported functions

View file

@ -160,7 +160,7 @@ void LuaMinimap::Register(lua_State *L)
{"__gc", gc_object},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<LuaMinimap>(L, methods, metamethods);
}
const char LuaMinimap::className[] = "Minimap";

View file

@ -77,7 +77,7 @@ void ModChannelRef::Register(lua_State *L)
{"__gc", gc_object},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<ModChannelRef>(L, methods, metamethods);
}
void ModChannelRef::create(lua_State *L, const std::string &channel)

View file

@ -186,7 +186,7 @@ const char NodeMetaRef::className[] = "NodeMetaRef";
void NodeMetaRef::Register(lua_State *L)
{
registerMetadataClass(L, className, methodsServer);
registerMetadataClass<NodeMetaRef>(L, methodsServer);
}
@ -211,7 +211,7 @@ const luaL_Reg NodeMetaRef::methodsServer[] = {
void NodeMetaRef::RegisterClient(lua_State *L)
{
registerMetadataClass(L, className, methodsClient);
registerMetadataClass<NodeMetaRef>(L, methodsClient);
}

View file

@ -84,7 +84,7 @@ void NodeTimerRef::Register(lua_State *L)
{"__gc", gc_object},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<NodeTimerRef>(L, methods, metamethods);
// Cannot be created from Lua
//lua_register(L, className, create_object);

View file

@ -101,7 +101,7 @@ void LuaValueNoise::Register(lua_State *L)
{"__gc", gc_object},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<LuaValueNoise>(L, methods, metamethods);
lua_register(L, className, create_object);
@ -360,7 +360,7 @@ void LuaValueNoiseMap::Register(lua_State *L)
{"__gc", gc_object},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<LuaValueNoiseMap>(L, methods, metamethods);
lua_register(L, className, create_object);
@ -449,7 +449,7 @@ void LuaPseudoRandom::Register(lua_State *L)
{"__gc", gc_object},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<LuaPseudoRandom>(L, methods, metamethods);
lua_register(L, className, create_object);
}
@ -562,7 +562,7 @@ void LuaPcgRandom::Register(lua_State *L)
{"__gc", gc_object},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<LuaPcgRandom>(L, methods, metamethods);
lua_register(L, className, create_object);
}
@ -652,7 +652,7 @@ void LuaSecureRandom::Register(lua_State *L)
{"__gc", gc_object},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<LuaSecureRandom>(L, methods, metamethods);
lua_register(L, className, create_object);
}

View file

@ -69,8 +69,27 @@ RemotePlayer *ObjectRef::getplayer(ObjectRef *ref)
// Exported functions
int ObjectRef::mt_tostring(lua_State *L)
{
auto *ref = checkObject<ObjectRef>(L, 1);
if (getobject(ref)) {
if (auto *player = getplayer(ref)) {
lua_pushfstring(L, "ObjectRef (player): %s", player->getName().c_str());
} else if (auto *entitysao = getluaobject(ref)) {
lua_pushfstring(L, "ObjectRef (entity): %s (id: %d)",
entitysao->getName().c_str(), entitysao->getId());
} else {
lua_pushfstring(L, "ObjectRef (?): %p", ref);
}
} else {
lua_pushfstring(L, "ObjectRef (invalid): %p", ref);
}
return 1;
}
// garbage collector
int ObjectRef::gc_object(lua_State *L) {
int ObjectRef::gc_object(lua_State *L)
{
ObjectRef *obj = *(ObjectRef **)(lua_touserdata(L, 1));
delete obj;
return 0;
@ -2806,9 +2825,10 @@ void ObjectRef::Register(lua_State *L)
{
static const luaL_Reg metamethods[] = {
{"__gc", gc_object},
{"__tostring", mt_tostring},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<ObjectRef>(L, methods, metamethods);
}
const char ObjectRef::className[] = "ObjectRef";

View file

@ -6,6 +6,7 @@
#include "lua_api/l_base.h"
#include "irrlichttypes.h"
#include <lua.h>
class ServerActiveObject;
class LuaEntitySAO;
@ -48,6 +49,9 @@ private:
// Exported functions
// __tostring metamethod
static int mt_tostring(lua_State *L);
// garbage collector
static int gc_object(lua_State *L);

View file

@ -44,7 +44,7 @@ void PlayerMetaRef::create(lua_State *L, ServerEnvironment *env, std::string_vie
void PlayerMetaRef::Register(lua_State *L)
{
registerMetadataClass(L, className, methods);
registerMetadataClass<PlayerMetaRef>(L, methods);
}
const char PlayerMetaRef::className[] = "PlayerMetaRef";

View file

@ -362,7 +362,7 @@ void LuaSettings::Register(lua_State* L)
{"__gc", gc_object},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<LuaSettings>(L, methods, metamethods);
// Can be created from Lua (Settings(filename))
lua_register(L, className, create_object);

View file

@ -36,7 +36,7 @@ void StorageRef::create(lua_State *L, const std::string &mod_name, ModStorageDat
void StorageRef::Register(lua_State *L)
{
registerMetadataClass(L, className, methods);
registerMetadataClass<StorageRef>(L, methods);
}
IMetadata* StorageRef::getmeta(bool auto_create)

View file

@ -425,7 +425,7 @@ void LuaVoxelManip::Register(lua_State *L)
{"__gc", gc_object},
{0, 0}
};
registerClass(L, className, methods, metamethods);
registerClass<LuaVoxelManip>(L, methods, metamethods);
// Can be created from Lua (VoxelManip())
lua_register(L, className, create_object);