Parenting Instances to Metatables?

Hello,

I’m working on a custom environment. I want to proxy the method, workspace::GetChildren(), which I do successfully via the below code:

local oldworkspace = workspace
local env = getfenv()

local Workspace = setmetatable({}, {
	__index = function(self, i) 
		if i == "GetChildren" then
			return function(self)
				print("Running through proxied function!")
			end
		end
		local index = oldworkspace[i]
		if type(index) == "function" then
			return setmetatable({}, {
				__call = function(self, ...)
					index(oldworkspace, table.unpack({...}))
				end,
			})
		end
		return index
	end,
})

env.workspace = Workspace

setfenv(1, env)

workspace:GetChildren() --// Running through proxied function!

However, an issue arises. How can I let users using my environment reliably set the Parent property of instances to my own Workspace metatable?

For example, when running the below code in my custom environment,

local Part = Instance.new("Part")
Part.Parent = workspace

an error occurs:
invalid argument #3 (Instance expected, got table)

My goal is to let users set the Parent property of any instance to my custom Workspace metatable - and make it actually parent to the real Workspace. How can I achieve this, without changing any syntax on the user end?

There is no way to do this, because there are no ways to overwrite how a property is set. You would have to add a key for the real workspace (i.e. Part.Parent = workspace.Real)

Just don’t do this. You lose performance, type checking, autocomplete and syntax highlighting when try to override Roblox API. Just have a normal GetChildren function that applies what you want onto the normal workspace/GetChildren.

Since there’s “no” way to do this a normal way, I’m going to have to create a metatable/proxy for every new Instance mentioned in the script, and set a __newindex metamethod (for “Parent”). This means proxying Instance.new, variables, and more. I made this post to see if there was a better, less “hacky” way of approaching this.

I have to, haha. No reason I’d want to do this if it wasn’t necessary!

1 Like

can you elaborate alittle on why? I feel like there is a better way to do this

All I can say is that I’m making a custom environment, and I want to create my own workspace::GetChildren() method to return what I want. I also want it to be possible to use regular syntax to set the Parent of instances to workspace.

Proxy Instance so you can write a custom Instance.new() method that returns objects whose .Parent setter you can control.

Yup, that’s what I’ll have to resort to, as I explained here:

ah, then i think the better way to handle this is with OOP (Object Oriented Programming)

Map = {}
Map.__index = Map

function Map.new(mapModel)
    local self = setmetatable({}, Map)
    self.Instance = mapModel

    return self
end

function Map:GetChildren()
    -- Here u can add what ever you would like

    -- Generic example
    return self.Instance:GetChildren()
end

Then u can easily create new worlds like this

local MapModule = require(wtv.Map)

local newMap = MapModule.new()

more reference if needed : All about Object Oriented Programming

Haha, no. Not making worlds. This is barely for game development - more-so pure Lua syntax.

I think you got confused when I said environment - not the real-life environment. Talking about the global environment of my sandbox.