SUNC Instance Utilities
The Roblox Instance API is wide but not bottomless. Several properties are flagged as "not accessible to scripts", signal connections are normally write-only, and instances parented to nil aren't reachable from any tree walk. SUNC adds the primitives that let scripts touch all of that — read hidden properties, enumerate connections, find detached instances.
gethiddenproperty / sethiddenproperty
Roblox annotates some instance properties as security-locked or internal — they exist in the engine but Lua can't see them through normal access. gethiddenproperty reads those values anyway; sethiddenproperty writes them.
gethiddenproperty(instance: Instance, property: string): (any, boolean)
sethiddenproperty(instance: Instance, property: string, value: any): boolean(any, boolean)local part = workspace:WaitForChild("TestPart")
local value, wasHidden = gethiddenproperty(part, "DataCost")
print(value, wasHidden) --> 20 trueCommon targets: DataCost, internal-only mesh attributes, replication flags, and a handful of debug properties Roblox exposes to internal tooling. None of these are documented externally, so what's actually accessible shifts as the engine evolves.
getconnections
Every Roblox event keeps a list of connected listeners internally. getconnections hands you that list as an array of connection objects you can inspect, disable, or fire manually.
getconnections(signal: RBXScriptSignal): { Connection }Each returned Connection has:
.Function— the listener closure..Thread— the coroutine the listener runs on (if applicable)..Connected— whether it's still active.:Fire(...)— invoke this listener immediately with the given arguments.:Disable()/:Enable()— toggle without disconnecting.:Disconnect()— remove the listener entirely.
local part = workspace.LavaBrick
for _, conn in getconnections(part.Touched) do
print(conn.Function)
conn:Disable() -- temporarily stop the lava
end{ Connection }Two things this enables in practice. First, disabling damage on yourself locally by switching off the right .Touched handlers — a server with proper validation will catch the tampering, but in unauthoritative games it works. Second, replaying a signal: call :Fire on a stored connection to run its handler manually, bypassing whatever gating the game put around the real fire site.
firesignal
Fire all listeners of a signal directly, as if the engine had fired the event itself.
firesignal(signal: RBXScriptSignal, ...: any): ()voidfiresignal(workspace.LavaBrick.Touched, workspace.CurrentCamera)
-- Every Touched handler runs as if the camera had touched the brick.getnilinstances
When an instance has its Parent set to nil, it's still alive — it just isn't in the data model. Roblox uses this to stash instances out of the way: temporary objects, internal state, partially-built structures. getnilinstances enumerates all of them.
getnilinstances(): { Instance }{ Instance }for _, inst in getnilinstances() do
print(inst.ClassName, inst.Name)
endThe classic use is finding hidden chat handlers, internal replication queues, or temporary GUIs the game has stashed here. A surprising amount of game state ends up here in larger codebases.
fireproximityprompt
ProximityPrompts are normally fired by the player holding the interaction key. This bypasses the player input requirement and fires the prompt as if the local player had completed the interaction.
fireproximityprompt(prompt: ProximityPrompt): ()voidlocal prompt = workspace.Chest.Interaction
fireproximityprompt(prompt) -- equivalent to holding E for the full durationNote that this only works on the client. The server still receives the trigger event because that's how prompts are replicated, but if the server validates against expected timing (most don't — but some do), the difference can be detected.
getrawmetatable, setrawmetatable, getnamecallmethod
Lower-level metatable access. Roblox normally prevents scripts from changing instance metatables; SUNC unlocks it.
getrawmetatable(obj: any): any
setrawmetatable(obj: any, mt: any): ()
getnamecallmethod(): string
setnamecallmethod(name: string): ()getrawmetatable(obj) returns the metatable even if it's normally hidden. setrawmetatable lets you replace it. These are the primitives you build hooks on top of — usually through hookmetamethod, which is itself implemented in terms of these.
getnamecallmethod works only inside a namecall hook: it returns the name of the method that triggered the hook. Used to dispatch within a single __namecall override:
local original
original = hookmetamethod(game, "__namecall", newcclosure(function(self, ...)
local method = getnamecallmethod()
if method == "Kick" and self == game.Players.LocalPlayer then
return -- silently drop only Kick calls
end
return original(self, ...)
end))Reflection helpers: getgenv / getrenv / getsenv
Three environment getters. All return the global table for a different context — useful when you need to add globals visible to specific scripts.
getgenv()— the executor's shared global table. Everything you put here is visible to every executor script that runs after.getrenv()— Roblox's own environment. Contains the standard library, services, and game-side globals.getsenv(script: LuaSourceContainer)— the environment of a specific script. Useful for reading a game script's locals after it ran.
getgenv().myCache = {}
-- Visible to every subsequent script run inside the executor
local serverScript = game.ServerScriptService.Combat
local env = getsenv(serverScript)
print(env.MAX_HEALTH) -- read a local from another scriptPutting it together
A small example combining several of these: a "reveal all hidden GUIs" one-liner that pulls every ScreenGui out of nil-parented limbo and reparents it under CoreGui where you can see it.
local coreGui = cloneref(game:GetService("CoreGui"))
for _, inst in getnilinstances() do
if inst:IsA("ScreenGui") then
inst.Parent = coreGui
end
endOne reflection call (getnilinstances), one cache alias (cloneref), three lines, all hidden UIs made visible. That density is the point of these utilities — each one does a single small thing the standard Roblox API doesn't.
Wrap-up
The instance-utility surface is the "long tail" of SUNC: a lot of small functions, each addressing a specific gap in the stock Roblox API. They're the kind of thing you don't miss until you need one, and then you reach for the docs and there it is. Skim them once so you know the shape; come back when a real problem matches.
Ather is the lead developer behind Atherhub. He's been writing Luau and Roblox tooling for the better part of a decade, with a focus on the messy interface between game-script internals and the platforms that host them. Have feedback on this article? Drop it in the Discord.