hookmetamethod
Hooks a specific metamethod on an object's metatable.
function hookmetamethod(object: table, method: string, hook: function): functionSynopsis
How it works
Resolves the metatableMetatableA table attached to another table (or userdata) that defines operator overloading via metamethods (__index, __newindex, __call, etc.). Roblox Instances use shared read-only metatables for method dispatch. of
object (bypassing __metatable guards like getrawmetatable), looks up the specified metamethodMetamethodA function in a metatable that overrides default behavior for operations like indexing (__index), assignment (__newindex), calling (__call), comparison (__eq), and arithmetic (__add, __mul, etc.)., and applies hookfunction to it. Returns a trampolineTrampolineA wrapper function that bounces (redirects) calls to another function. In executor context, newcclosure creates a C closure trampoline that calls the Luau function stored in its first upvalue. to the original metamethod. Because Roblox Instances share a single global metatable, hooking on any InstanceInstanceThe base class for all Roblox objects (Parts, Models, Scripts, GUIs, etc.). Instances form a tree hierarchy (the DataModel). In Luau, they appear as userdata with shared metatables. affects all Instances.VM internals — NAMECALL dispatch
When Luau compiles colon-call syntax
obj:Method(args), it emits two instructions:
NAMECALL R(A), R(B), K(C) -- look up method name K(C) on R(B)
CALL R(A), nargs, nrets -- call the resolved function
NAMECALL is a 32-bit instruction: bits [0:7] = opcode, [8:15] = A register, [16:23] = B register, [24:31] = aux (constant index stored in nextnext()Table traversal primitive. next(t, key) returns the next key-value pair after key, or nil when done. next(t, nil) returns the first pair. The underlying function used by pairs(). Traversal order is not guaranteed. word). The VM first tries a fast-path lookup on the object's metatableMetatableA table attached to another table (or userdata) that defines operator overloading via metamethods (__index, __newindex, __call, etc.). Roblox Instances use shared read-only metatables for method dispatch. __index. If the object is a userdataUserdataA Luau type for C-allocated memory blocks. Roblox Instances, Vector3s, CFrames, and other engine types are userdata with metatables providing their API. Cannot be created from Luau directly. with __namecall, the VM calls that metamethodMetamethodA function in a metatable that overrides default behavior for operations like indexing (__index), assignment (__newindex), calling (__call), comparison (__eq), and arithmetic (__add, __mul, etc.). directly and sets an internal namecall register to the method name string. Inside the hook, getnamecallmethod() reads this register.Shared metatable implication
All Roblox Instances (
Part, Model, RemoteEvent, etc.) share a single metatableMetatableA table attached to another table (or userdata) that defines operator overloading via metamethods (__index, __newindex, __call, etc.). Roblox Instances use shared read-only metatables for method dispatch. at the C++ level. Hooking __namecall on game intercepts every :Method() call on every InstanceInstanceThe base class for all Roblox objects (Parts, Models, Scripts, GUIs, etc.). Instances form a tree hierarchy (the DataModel). In Luau, they appear as userdata with shared metatables. in the game. This is why a single hook can intercept :FireServer(), :FindFirstChild(), :GetService(), etc.Common hooks
__namecall— intercept all method calls (:FireServer,:FindFirstChild, etc.)__index— intercept property reads (obj.Property). Dispatched byGETTABLEKSopcode__newindex— intercept property writes (obj.Property = value). Dispatched bySETTABLEKSopcode__tostring— control string representation (called bytostring())
Usage
Intercept __namecall on game
local origNamecall
origNamecall = hookmetamethod(game, "__namecall", function(self, ...)
local method = getnamecallmethod()
if method == "FireServer" then
print("RemoteEvent fired:", ...)
end
return origNamecall(self, ...)
end)Parameters
object table | userdata The object whose metatable contains the metamethod to hook.
method string The metamethod name, e.g. "__namecall", "__index", "__newindex".
hook function The replacement function.
Returns
function A trampoline to the original metamethod implementation.
Recursive Loop Risk
Inside __namecall hooks, always use the trampoline with dot syntax (original(self, ...)) to avoid an infinite recursion loop. Using colon syntax will re-invoke the hook.