I made myself a class module so I can easily create custom objects. It has some of the functionality of Roblox instances, like parents/children, ClassName, and Name.
Also, I used __newindex
to create read-only values (_name) and make values that I can both read from and set to while allowing set to have a callback.
The callbacks are all listed in setFunctions
. Currently, I only have one for Parent, which adds it to the _children
list of its parent, if the parent is a custom instance too.
Is this the best way to accomplish my goal? Should I add anything to it?
local require = require(game:GetService("ReplicatedStorage").Require)
local events = require("Events")
local setFunctions = {
Parent = function(self, value)
self:_addAsChild(value)
end,
_childAdded = function(self, _, value)
self:_addChild(value)
end
}
local instance = {}
instance.__index = instance
instance.__newindex = function(self, key, value)
if key:sub(1, 1) == "_" then return end
if setFunctions[key] then setFunctions[key](self, value) end
rawset(self, key, value)
self.Changed:Fire(key, value)
if self._propertyChangedEvents[key] then
self._propertyChangedEvents[key]:Fire(value)
end
end
function instance.new(name)
return setmetatable({
Changed = events.new(),
ClassName = name,
Parent = nil,
Name = nil,
_waitForChildEvents = {},
_propertyChangedEvents = {},
_children = {},
}, instance)
end
function instance:_addAsChild(parent)
if not parent._children then return end
table.insert(parent._children, self)
parent:_addChild(self)
end
function instance:GetChildren()
return self._children
end
function instance:GetPropertyChangedSignal(property)
local newEvent = self._propertyChangedEvents[property] or events.new()
self._propertyChangedEvents[property] = newEvent
return newEvent
end
function instance:WaitForChild(name)
warn("Use of WaitForChild. Have you considered using events?")
if self._children[name] then return self._children[name] end
local waitEvent = self._waitForChildEvents[name] or events.new()
self._waitForChildEvents[name] = waitEvent
return waitEvent:Wait()
end
function instance:Destroy()
for i, item in ipairs(self._children) do
if item.Destroy then
item:Destroy()
else
self:_clear(item)
end
end
if self.Parent._children then
table.remove(self.Parent._children, table.find(self.Parent._children, self))
end
self:_clear(self)
setmetatable(self, nil)
end
function instance:_addChild(value)
if not self._waitForChildEvents[value.Name or "_&unusableName"] then return end
self._waitForChildEvents[value.Name]:Fire(value)
self._waitForChildEvents[value.Name]:Destroy()
end
function instance:_clear(obj)
for x = 1, #self do
self[x] = nil
end
end
setmetatable(instance, {
__call = function(self, ...)
return self.new(...)
end
})
return instance
--// thanks for stopping by
and here’s the code where i test it:
local instance = require("Instance")
local newInstance = instance.new("hm")
print(newInstance.ClassName) --> hm
local thisInstance = instance.new("hm2")
thisInstance.Parent = newInstance
print(newInstance:GetChildren()[1].ClassName == thisInstance.ClassName) --> true
print(thisInstance.Parent == newInstance) --> true
thisInstance:Destroy()
print(newInstance:GetChildren()[1]) --> nil
--// (supposed to be nil since it was destroyed)
coroutine.wrap(function()
wait(4)
local thirdInstance = instance.new("hm3")
thirdInstance.Name = "third"
thirdInstance.Parent = newInstance
end)()
local third = newInstance:WaitForChild("third")
print(third) --> table: debugId