BaseObject
BaseObject provides interface methods for three core features:
- Object Destruction via adding a :Destroy() method and Destroyed flag property,
- Task Management across the objects lifetime by providing a janitor internally,
- and Signal Management by providing interfaces to Register, Get, and Fire signals easily.
Destroy Behavior:
- When a BaseObject instance is destroyed, it's
Destroyedproperty is set to true, and it'sDestroyedsignal is fired. - It's metatable is set to a metatable that will error when any of it's methods or metamethods are called.
You should check Destroyed before calling any methods on a BaseObject instance if you are not sure if it has been destroyed or not.
Types
BaseObject
Properties
ClassName
This item is read only and cannot be modified. Read OnlystaticBaseObject.ClassName: stringSignalBehavior
staticBaseObject.SignalBehavior: Enum.SignalBehaviorDetermines the default signal behavior for signals fired from this BaseObject via FireSignal.
Destroyed
This item is read only and cannot be modified. Read OnlyBaseObject.Destroyed: boolean?Indicates whether or not the object has been destroyed.
local obj = BaseObject.new()
print(obj.Destroyed) -- nil
obj:Destroy()
print(obj.Destroyed) -- true
Functions
getObjectFromId
staticFetches the object with the given ID if it exists.
local obj = BaseObject.new()
local id = obj:GetId()
print(BaseObject.getObjectFromId(id) == obj) -- true
isDestroyed
staticChecks whether or not the object is destroyed.
local obj = BaseObject.new()
print(BaseObject.isDestroyed(obj)) -- false
obj:Destroy()
print(BaseObject.isDestroyed(obj)) -- true
new
staticConstructs a new BaseObject
local obj = BaseObject.new({
X = 1,
Y = 2,
})
obj.Z = 3
print(obj.X, obj.Y, obj.Z) -- 1, 2, 3
local SuperClass = BaseObject
local MyClass = setmetatable({}, SuperClass)
MyClass.__index = MyClass
MyClass.ClassName = "MyClass"
function MyClass.new()
local self = setmetatable(SuperClass.new(), MyClass)
-- Custom logic here
return self
end
function MyClass:Destroy() -- Overwrite the BaseObject Destroy method
SuperClass.Destroy(self) -- If you overwrite the BaseObject Destroy method you need to have this line to call the original.
end
function MyClass:Print()
print("Hello, World!")
end
return MyClass
Destroy
BaseObject:Destroy() → ()Marks the Object as Destroyed, fires the Destroyed Signal, cleans up the BaseObject, and sets the metatable to nil/a special locked MT.
Overriding
If you override this method, you need to make sure you call
SuperClass.Destroy(self) to call the superclass methods.
function MyCustomClass:Destroy()
SuperClass.Destroy(self) -- calls the superclass method to clean up events, tasks, etc..
end
GetId
BaseObject:GetId() → numberReturns the ID of the BaseObject Can be used to fetch the object with BaseObject.getObjectFromId(id)
IsA
BaseObject:IsA(classOrClassName: {[any]: any} | string--
The class or class name to check against
) → booleanReturns true if the given object is of a given class. Takes a class name or class object.
GetTask
BaseObject:GetTask(taskId: any) → Task?Fetches the task with the given ID if it exists.
local obj = BaseObject.new()
local part = Instance.new("Part")
obj:AddTask(part, nil, "Test")
print(obj:GetTask("Test") == part) -- true
AddTask
BaseObject:AddTask(task: Task,taskCleanupMethod: (string | true | nil)?,--
(if none is given it will try to infer; Passing true tells it to call it as a function)
taskId: any?) → Task--
The task that was given
Adds a task to the janitor. If a taskId is provided, it will be used as the key for the task in the janitor and can then be fetched later with :GetTask(). If an ID is provided and there already exists a task with that ID, it will clean up the existing task and then replace the index with the new one. It will return the task that was added/given.
local obj = BaseObject.new()
local task = obj:AddTask(function()
print("Hello, World!")
end)
obj:Destroy() -- Prints "Hello, World!"
yielding
Avoid yielding within added tasks as it may cause unexpected behavior during destruction.
AddPromise
BaseObject:AddPromise(prom: Promise) → PromiseAdds a promise to the janitor. Similar to :AddTask(). Returns the same Promise that was given to it.
local prom = Promise.delay(math.random(10))
local obj = BaseObject.new()
obj:AddPromise(prom)
task.wait(math.random(10))
obj:Destroy() -- Cancels the promise if it hasn't resolved yet
RemoveTask
BaseObject:RemoveTask(taskId: any,dontClean: boolean?) → ()Removes a task from the janitor. Cleans the task as if :DoCleaning was called. If dontClean is true, it will not clean up the task, it will just remove it from the janitor.
local obj = BaseObject.new()
local task = obj:AddTask(function()
print("Hello, World!")
end, nil, "Test")
obj:RemoveTask("Test") -- Prints "Hello, World!"
RemoveTaskNoClean
BaseObject:RemoveTaskNoClean(taskId: any) → ()Removes a task from the janitor without cleaning it.
local obj = BaseObject.new()
local task = obj:AddTask(function()
print("Hello, World!")
end, nil, "Test")
obj:RemoveTaskNoClean("Test") -- Does NOT print "Hello, World!"
FireSignal
BaseObject:FireSignal(signalName: string,--
The name of the signal to fire
...: any--
Arguments to pass to the signal
) → ()Fires the signal with the given name, if it exists.
deferred signals
If the BaseObject's SignalBehavior is not set to Immediate, signals will be fired deferred.
local obj = BaseObject.new()
local SignalName = "Test"
obj:RegisterSignal(SignalName)
obj:GetSignal(SignalName):Connect(print)
obj:FireSignal(SignalName, "Hello, World!") -- Fires the signal with the argument "Hello, World!"
RegisterSignal
BaseObject:RegisterSignal(signalName: string--
Name of signal to register
) → ()Marks a signal with the given name as registered. Does not actually build a new signal, it sets the index to a SignalMarker to identify it as registered so that it can be fetched later.
This is mainly here to just enforce good patterns with registering signals before fetching them.
HasSignal
BaseObject:HasSignal(signalName: string) → booleanChecks whether or not a signal with the given name is registered.
local obj = BaseObject.new()
local SignalName = "Test"
print(obj:HasSignal(SignalName)) -- false
obj:RegisterSignal(SignalName)
print(obj:HasSignal(SignalName)) -- true
GetSignal
BaseObject:GetSignal(signalName: string) → SignalFetches a signal with the given name. Creates the Signal JIT.
ConnectSignal
BaseObject:ConnectSignal(signalName: string,--
The name of the signal to connect to
func: (...any) → ()--
The function to connect
) → Connection--
The connection object
Connects a function to a signal with the given name. Creates the signal JIT.
Shorthand for :GetSignal(signalName):Connect(func).
GetDestroyingSignal
BaseObject:GetDestroyingSignal() → SignalReturns a signal that fires when the object is being destroyed. Creates the signal JIT.
The Destroying signal is unique in that it always fires immediately instead of deferred.
local obj = BaseObject.new()
obj:GetDestroyingSignal():Connect(function()
print("Object Destroying!")
end)
obj:Destroy() -- Prints "Object Destroying!"
GetDestroyedSignal
BaseObject:GetDestroyedSignal() → SignalReturns a signal that fires when the object is destroyed. Creates the signal JIT.
local obj = BaseObject.new()
obj:GetDestroyedSignal():Connect(function()
print("Object Destroyed!")
end)
obj:Destroy()
BindToInstance
BaseObject:BindToInstance(destroyOnNilParent: boolean?--
Whether or not to destroy the object when the parent is nil'd
) → function--
Disconnects the binding
Binds the object to the given instance. When the object is destroyed, it will destroy the instance. When the instance is destroyed, it will destroy the object.
local obj = BaseObject.new()
local part = Instance.new("Part")
obj:BindToInstance(part)
do -- setup prints on destroy
obj:AddTask(function()
print("Object Destroyed!")
end)
part.Destroying:Connect(function()
print("Part Destroyed!")
end)
end
local X = if math.random(1,2) == 1 then obj or part
X:Destroy() -- Prints "Object Destroyed!" and "Part Destroyed!" (Destroying one will destroy the other)