Instance Event Handler Module

This module was made out of boredom and need for organization

This is an open sourced module that is used to organize instance events(EX: part.Touched, button.MouseButton1Up, RemoteEvent.OnServerEvent, RunService.Heartbeat, etc) and have more control over them in general. A basic scripting knowledge is highly recommended



Source code for you to copy and paste

Summary
local module = {}

local Players = game:GetService("Players")



local BindedEvents= {
	
}

local function GetTabForInstanceId(id)	
	return BindedEvents[id]
end

local function SetTabForInstanceId(id, tab)
	BindedEvents[id] = tab
end


local function GetTabForInstance(obj, instanceNameTab)
	for _,v in ipairs(instanceNameTab) do
		if v.Instance == obj  then
			return v
		end
		
	end
end


local function FindEvent(event, EventsTab)
	for i,v in ipairs(EventsTab) do
		if v.Event == event  then
			return v,i
			
		end
	end
end

local function FindEventConnection(event, EventsTab)
	for i,v in ipairs(EventsTab) do
		if v.Event == event  then
			return v.Connection
		end
	end
end


local function GetEventFunctionsTab(event, EventsTab)
	for i,v in ipairs(EventsTab) do
		if v.Event == event  then
			return v.Functions
		end
	end
end



local function RunFunction(func,DebugError, ...)--This exucutes "func"
	if not DebugError then 
	coroutine.resume(coroutine.create(func) ,...)
		
	else 
		coroutine.resume(coroutine.create(function(func,...)
			local suc,err = pcall(func,...)
			
			if not suc then 
				warn("[Instance Event Handler]:", err)
			end
			
		end),func,...)
		
	end
	
end
local function RunFunctions(tab ,...)--This run all the functions in "tab"
	for i,v in ipairs(tab.Functions) do
		if v.returnSelf then
			RunFunction(v.Function, v.DebugError, v.returnTab, ...)
		else 
			RunFunction(v.Function, v.DebugError, ...)
		end
	end
end


local function CreateEvent(obj:Instance, EventTab, EventType:string, event, ExistingTab)
	local tab = ExistingTab or
	{
		Event = event,
		Connection = nil,
		Functions = {}

	}
	EventType = EventType:lower()
	if EventType == "normal" then
		
		tab.Connection = obj[event]:Connect(function(...)
			RunFunctions(tab,...)
		end)
		
	elseif  EventType == "property" or EventType == "p" then
		
		tab.Connection = obj:GetPropertyChangedSignal(event):Connect(function(...)
			RunFunctions(tab,...)
		end)
		
	elseif EventType == "attribute" or EventType == "a" then
		
		tab.Connection = obj:GetAttributeChangedSignal(event):Connect(function(...)
			RunFunctions(tab,...)
		end)
	
		
	end
	
	
	
	
	if not ExistingTab then
		table.insert(EventTab, tab)
	end
	
	return tab.Connection
end

local function UnbindEvent(Key, FunctionsTab)
	
	for i,v in ipairs(FunctionsTab) do
		if v.Key == Key then
			table.remove(FunctionsTab, i)
			return
		end
		
	end
	
end

local function RebindEvent(tab, FunctionsTab)
	table.insert(FunctionsTab, tab)
end



function module:BindEvent(id:string, instance:Instance, event:string , Function, returnSelf, EventType:string, DebugError:boolean, key:string)--Main function to create/bind an event
	
	local InstanceIdTab = GetTabForInstanceId(id)
	if not InstanceIdTab  then
		
		local NewTab = 
		
			{
				Instance = instance,		
				Events = {},		
			}
		
		 SetTabForInstanceId(id, NewTab) 
	end
	local Connection = FindEventConnection(event, BindedEvents[id].Events) or CreateEvent(instance, BindedEvents[id].Events, EventType or "Normal" , event)
	
	
	local EventFunctionsTab = GetEventFunctionsTab(event, BindedEvents[id].Events)
	local Key = key or ""..tick()	
	local FunctionTab = {
		Function = Function,
		Key = Key,
		returnSelf = returnSelf,
		DebugError = DebugError,
		returnTab = {
			Connection = Connection,
			Connected = true,
		},
	}
	table.insert(EventFunctionsTab, FunctionTab)	
	
	
	function FunctionTab.returnTab:Unbind()
		FunctionTab.returnTab.Connected = nil
		UnbindEvent(Key, EventFunctionsTab)
		
	end
	function FunctionTab.returnTab:Rebind()
	
		FunctionTab.returnTab.Connected = true
		RebindEvent(FunctionTab, EventFunctionsTab)
	end
	function FunctionTab.returnTab:Destroy()
		if FunctionTab.binded then
			UnbindEvent(Key, EventFunctionsTab)
		end
	
	FunctionTab = nil		
		
	end
	function FunctionTab.returnTab:SetNewFunction(Function)		
		FunctionTab.Function = Function
	end
	
	function FunctionTab.returnTab:Disconnect()
		FunctionTab.returnTab.Connection:Disconnect()
		FunctionTab.returnTab.Connected = false
	end
	
	function FunctionTab.returnTab:DeleteEvent()
		if FunctionTab.returnTab.Connection and FunctionTab.returnTab.Connection.Connected then
			FunctionTab.returnTab.Connection:Disconnect()
		end
		
		local EventTab,EventIndex = FindEvent(event, BindedEvents[id].Events)
		table.remove(BindedEvents[id].Events, EventIndex)
	end
	


	return FunctionTab.returnTab,FunctionTab
	 
end

function module:Clear(id:string)--This disconnects all the events that are descendants of "id"
	if typeof(id) ~= "string" then return end
	for i,v in pairs(BindedEvents) do
		if i == id  then
			local Events = v.Events
			
			if Events then
				for j,k in ipairs(Events) do
					if k.Connection and k.Connection.Connected then
						k.Connection:Disconnect()
					end
					
				table.remove(Events, j)	
				end
				
				
			end
			
			
			
		end
		
	end
	
	return true
end


function module:Debug()--This prints the container of all the event
	coroutine.resume(coroutine.create(print), BindedEvents)
end














return module



Explaining the main functions you are able to interact with

Summary
function module:BindEvent(id:string, instance:Instance, event:string , Function, returnSelf:boolean, EventType:string, DebugError:boolean, key:string)
...
end)
Simplification

"id": The id that will be used to store all the events of "instance"

"instance": The instance that will be used for connecting the event

"event": The name of the event that will be connected( Normal → ‘Touched’, ‘OnServerEvent’,‘OnClientEvent’, ‘MouseButton1Up’, ‘ChildAdded’, ‘ChildRemoved’, etc: Property → ‘Name’, ‘Parent’, ‘Transparency’, ‘Color’, ‘Text’, ‘Size’, ‘Position’, etc: Attribute → any attribute of an instance)

"Function": The callback function of the event being created

"returnSelf": indicates whether the table containing the event is passed as the first argument for the callback function

"EventType"(leave nil or nothing for default/Normal event): Indicates the type of of event that is required(nil or nothing->Normal, “property” or “p”->Property, “attribute” or “a”->Attribute)

"DebugError": Indicated whether errors caused by the callback function should be debugged

"Key"(optional): optionally accepts a key to be used instead of automatically creating one(ignore this argument is you don’t plan on manually making a key)


function module:Clear(id:string)--Clears/Disconnects all the events that is a descendant of the "id" and removes all of the events's components
...
end)



Functions from the result of calling module:BindEvent()
function eventObject:Unbind()--Unbind that specific callback function from the event so it can be rebinded later on when needed
...
end)

function eventObject:Rebind()--Re-binds that specific callback function to the event
...
end)

function eventObject:Destroy()--Completely removes that specific callback function from the event when no longer in use
...
end)

function eventObject:SetNewFunction(Function)--Sets the new callback function of this event object to "Function"
...
end)

function eventObject:Disconnect()--Disconnects the actual event that runs all the callback function that is connected to it
...
end)

function eventObject:DeleteEvent()--Disconnects the event and remove all the callback functions that is connected to it, basically deletes the event
...
end)



Example of module usage

Summary

Example 1


Code sample result1



Example 2




Example 3




Example 4


Code sample result4



Example 5






If you do decide to give this module a try, please leave some feedbacks on what features I could potentially add. However, if you feel that this module is impractical for usage, please leave a reply on your reason.


Also, feel free to ask any question about the module!



Thoughts on the module
  • I will consider using this module
  • I will definitely be using this module
  • Seems useless
  • Creative but impractical to use
  • Other(reply)

0 voters