molyi/butler

Butler

Installation

Pesde

pesde add molyi/butler

Wally

Butler = "molyi/butler@^1.2.0"

Why to use Butler?

  • Fully Typed: Designed to work with the new Luau type solver.
  • Performance: Uses a Doubly Linked List for O(1) Removal and LIFO cleanup structure.

Usage

Basics

local Butler = require(path.to.Butler)

-- Create a butler.
local butler = Butler.new()

-- Clean up an instance
local part = Instance.new("Part")
butler:Add(part, "Destroy")

-- Clean up a connection
butler:Connect(workspace.ChildAdded, function(child)
    print(child.Name)
end)

-- Run a function on cleanup
butler:Add(function()
    print("Cleanup started")
end, true)

-- Cleans everything
butler:Clean()

Signals

-- Standard
butler:Connect(RunService.Heartbeat, function(dt)
    print("Frame")
end)

-- Once
butler:Once(humanoid.Died, function()
    print("skill issue")
end)

-- Parallel
butler:ConnectParallel(part.Touched, function(hit)
    print("Touched in parallel")
end)

-- Disconnects automatically when butler is cleaned
local cn = butler:Connect(part.Touched, print)
-- Or you can disconnect manually:
butler:Remove(cn)
-- Maybe without cleaning (Without disconnecting)
butler:RemoveNoClean(cn)

RenderStep

-- Binds and automatically unbinds on cleanup
local bind = butler:BindToRenderStep("Lag", Enum.RenderPriority.Camera.Value, function(dt)
    -- do something unoptimized to lag the game
end)

-- You can unbind by removing it from the butler or using butler:Clean()
butler:Remove(bind)

Instance Linking

local randomPart = workspace.Part
local cn = butler:AttachToInstance(randomPart)
-- If randomPart is destroyed, butler:Destroy() is called.

-- You can undo this link by removing the connection:
butler:Remove(cn)

Nesting

local mainButler = Butler.new()
local otherButler = mainButler:Extend()

otherButler:Connect(workspace.ChildAdded, print)

-- Cleaning 'mainButler' will also destroy 'otherButler'
mainButler:Clean()

API

Butler Static

MethodDescription
.new()Creates a new Butler instance.
.CleanupMethodsAn enum of valid cleanup methods: "Function", "Thread", "Disconnect", "Destroy".
.IsButler(obj)Returns true if obj is a Butler instance.

Butler

MethodDescription
.CurrentlyCleaningbooleantrue if the Butler is currently iterating through its cleanup tasks.
:Add(object, cleanupMethod?)Adds object to the cleanup list. Returns the object.
:Connect(signal, fn)Connects fn to signal and adds the connection to the Butler. Returns the Connection.
:ConnectParallel(signal, fn)Connects fn to signal in parallel and adds the connection to the Butler. Returns the Connection.
:Once(signal, fn)Connects fn to signal once. The connection is automatically removed from the Butler when fired. Returns the Connection
:BindToRenderStep(name, priority, fn)Wraps RunService:BindToRenderStep. Returns the unbinding function.
:Extend()Creates and returns a new "child" Butler. If the parent is cleaned/destroyed, the child is destroyed too.
:AttachToInstance(instance)Listens for instance.Destroying and calls :Destroy() on the Butler automatically. Returns the Connection.
:Remove(object)Removes object from the Butler and immediately cleans it (calls Destroy/Disconnect etc). Returns itself.
:RemoveNoClean(object)Removes object from the Butler without cleaning it. Returns the Butler itself.
:RemoveList(...objects)Calls :Remove() on all provided objects. Returns the Butler itself.
:RemoveListNoClean(...objects)Calls :RemoveNoClean() on all provided objects. Returns the Butler itself.
:Clean()Cleans all added objects in order. Returns the Butler itself.
:Destroy()Calls :Clean() and renders the Butler unusable.