garrysmod-requests
garrysmod-requests copied to clipboard
Reimplement debug.getregistry but with restrictions
Details
debug.getregistry
should be made functions again to not break compatibility with older addons, but it should have restrictions.
My idea would be to let debug.getregistry only return metatables and allow with a __newindex
function to add new metatables to the registry and to remove metatables.
They should only be able to be set if nothing with the name is registered in the registry.
Also, a __index
function should be added that allows one to get metatables from the registry, but the restriction there should be that only tables containing MetaName should be allowed.
By checking if a table in the registry has the MetaName
field as a key, we can check if it's a metatable.
How my approach would look:
LUA_FUNCTION(debug_getregistry__newindex)
{
const char* pKey = LUA->GetString(2);
if (!LUA->IsType(3, Type::Table) && !LUA->IsType(3, Type::Nil)) { return 0; } // If it's not a table or nil then just return.
LUA->PushSpecial(SPECIAL_REG);
LUA->GetField(-1, pKey);
if (LUA->IsType(-1, Type::NIL))
{
LUA->GetField(3, "MetaName");
if (LUA->IsType(-1, Type::Nil)) // Verify that our new Table has a MetaName field. If not, add it.
{
LUA->PushString(pKey);
LUA->SetField(3, "MetaName");
}
LUA->Pop(1);
LUA->Push(3);
LUA->SetField(-3, pKey);
} else if (LUA->IsType(-1, Type::Table)) { // Allow one to remove a metatable
LUA->GetField(-1, "MetaName");
if (LUA->IsType(-1, Type::String))
{
LUA->PushNil();
LUA->SetField(-4, pKey);
}
LUA->Pop(1);
}
LUA->Pop(2);
return 0;
}
LUA_FUNCTION(debug_getregistry__index)
{
const char* pKey = LUA->GetString(2);
LUA->PushSpecial(SPECIAL_REG);
LUA->GetField(-1, pKey);
if (LUA->IsType(-1, Type::Table))
{
LUA->GetField(-1, "MetaName");
if (LUA->IsType(-1, Type::String)) // If it has MetaID and MetaName it's a metatable.
{
LUA->Push(-2);
int reference = LUA->ReferenceCreate();
LUA->Pop(4);
LUA->ReferencePush(reference);
return 1;
}
LUA->Pop(1);
}
LUA->Pop(2);
return 0;
}
std::vector<const char*> entity_classes = {
"Entity",
"Player",
"Weapon",
"NPC",
"Vehicle",
"NextBot"
};
LUA_FUNCTION(debug_getregistry)
{
LUA->CreateTable();
// Push default Metatables to reduce __index calls.
LUA->PushSpecial(SPECIAL_REG);
for (int i=Type::Vector; i < (Type::COUNT-1); i++)
{
bool success = LUA->PushMetaTable(i);
if (!success) { continue; }
LUA->GetField(-1, "MetaName");
const char* pMetaName = LUA->GetString(-1);
LUA->Pop(2); // Pop MetaName and MetaTable
LUA->GetField(-1, pMetaName);
if (LUA->IsType(-1, Type::Table))
{
LUA->SetField(-3, pMetaName);
} else
{
LUA->Pop(1);
}
}
for (const char* pMetaName : entity_classes) // Add Entity Metatables. The loop above cannot handle these because they use the same type!
{
LUA->GetField(-1, pMetaName);
if (LUA->IsType(-1, Type::Table))
{
LUA->SetField(-3, pMetaName);
} else
{
LUA->Pop(1);
}
}
LUA->Pop(1);
// Set our Metatable
LUA->CreateTable();
LUA->PushCFunction(debug_getregistry__newindex);
LUA->SetField(-2, "__newindex");
LUA->PushCFunction(debug_getregistry__index);
LUA->SetField(-2, "__index");
LUA->SetMetaTable(-2);
return 1;
}
Where would i put this?
Compile it into a module.