Metatables

Read and modify metatables, including locked ones.

5 functionssUNC 100%Lynx 0.0.0

Roblox locks the metatables of its objects: getmetatable(game) returns the string "The metatable is locked" instead of the table. These functions go around the lock.

Reading

getrawmetatable

since 1.0.0
getrawmetatable(object: any): table?

Returns the metatable of object, ignoring any __metatable field. Returns nil if it has none.

Parameters

objectany
Any value: a table, an Instance, a userdata.

Returns

table?

The real metatable.

Example

print(getmetatable(game)) --> The metatable is locked
local mt = getrawmetatable(game)
print(typeof(mt.__index)) --> function
print(typeof(mt.__namecall)) --> function

isreadonly

since 1.0.0
isreadonly(t: table): boolean

Returns whether t is read-only. Equivalent to table.isfrozen.

Parameters

ttable
The table to check.

Returns

boolean

true if t can't be modified.

Example

print(isreadonly(getrawmetatable(game))) --> true
print(isreadonly({})) --> false

Writing

setrawmetatable

since 1.0.0
setrawmetatable(object: any, metatable: table?): any

Sets the metatable of object, ignoring __metatable protection. Returns object.

Parameters

objectany
The value whose metatable to replace.
metatabletable?
The new metatable, or nil to remove it.

Returns

any

object, for chaining.

Example

local locked = setmetatable({}, { __metatable = "locked" })
-- setmetatable(locked, {}) would error here.
setrawmetatable(locked, {
__index = function(_, key)
return key .. "!"
end,
})
print(locked.hello) --> hello!

setreadonly

since 1.0.0
setreadonly(t: table, readonly: boolean): ()

Sets whether t is read-only. Roblox freezes its metatables and many library tables, so unfreeze them before assigning fields, and freeze them again when you're done.

Parameters

ttable
The table to change.
readonlyboolean
true to freeze, false to unfreeze.

Example

local mt = getrawmetatable(game)
local oldIndex = mt.__index
setreadonly(mt, false)
mt.__index = newcclosure(function(self, key)
return oldIndex(self, key)
end)
setreadonly(mt, true)

Namecall

getnamecallmethod

since 1.0.0
getnamecallmethod(): string?

Returns the name of the method that triggered the current __namecall, such as "FireServer" for remote:FireServer().

Only meaningful inside a __namecall hook. Read it before yielding, because the value belongs to the current call.

Returns

string?

The method name.

Example

local counts = {}
local original
original = hookmetamethod(game, "__namecall", newcclosure(function(self, ...)
local method = getnamecallmethod()
counts[method] = (counts[method] or 0) + 1
return original(self, ...)
end))
task.wait(10)
for method, n in counts do
print(method, n)
end