Accidentally edited my last message.
Here’s the module
--vojin154 copyright :D
local Hooks = {}
---------------------------------SERVICE HOOKS----------------------------------
Hooks._function_hooks = {}
Hooks._run_service_hooks = {}
function Hooks:AddHook(object, func, id, callback)
id = tostring(id)
if not self:IsValidHook(object, func, id, callback) then
pcall(error("[HOOKS] FAILED TO HOOK " .. object .. " WITH " .. func))
return
end
self:CheckHooks(object, func)
if object == "RunService" and id ~= "RunServiceHooks" then
--pcall(error("[HOOKS] TRIED TO HOOK RUNSERVICE IN THE WRONG PLACE. PLEASE USE HookRunService() INSTEAD"))
pcall(error(debug.traceback("[HOOKS] TRIED TO HOOK RUNSERVICE IN THE WRONG PLACE. PLEASE USE HookRunService() INSTEAD")))
return
end
if self._function_hooks[object][func][id] then
pcall(error("[HOOKS] HOOK ID ALREADY EXISTS: " .. id))
return
end
self._function_hooks[object][func][id] = callback
return id
end
function Hooks:HookRunService(id, waitTime, callback)
waitTime = waitTime or 0
self._run_service_hooks[id] = {
callback = callback,
waitTime = waitTime,
t = waitTime
}
return id
end
function Hooks:RemoveRunServiceHook(id)
if self._run_service_hooks[id] then
self._run_service_hooks[id] = nil
end
end
function Hooks:RemoveHook(id)
self:RemoveTableEntry(id, self._function_hooks)
end
---------------------------------EVENT HOOKS------------------------------------
Hooks._event_hooks = {}
function Hooks:HookEvent(object, event, id, callback)
if (not object) or (not event) or (not object[event]) or (not id) or (id == "") or not callback or (type(callback) ~= "function") then
pcall(error("[HOOKS] FAILED TO HOOK " .. object .. " WITH " .. event))
return
end
self:CheckEvents(object, event)
if self._event_hooks[object][event][id] then
pcall(error("[HOOKS] HOOK ID ALREADY EXISTS: " .. id))
return
end
self._event_hooks[object][event][id] = callback
return id
end
function Hooks:RemoveEvent(id)
self:RemoveTableEntry(id, self._event_hooks)
end
---------------------------------UTIL FUNCTIONS---------------------------------
function Hooks:GetHook(id)
for _, object in pairs(self._function_hooks) do
for _, func in pairs(object) do
for i, v in pairs(func) do
if i == id then
return i, v
end
end
end
end
end
function Hooks:GetEvent(id)
for _, object in pairs(self._event_hooks) do
for _, event in pairs(object) do
for i, v in pairs(event) do
if i == id then
return i, v
end
end
end
end
end
---------------------------------CORE FUNCTIONS---------------------------------
local function isValid(object, method, id, callback)
local function isntEmpty(str)
return str ~= ""
end
if object and method and id and callback and (type(callback) == "function") then --Split the if statements for better readability
if isntEmpty(object) and isntEmpty(method) and isntEmpty(id) then
return true
end
end
end
function Hooks:IsValidHook(object, func, id, callback)
return (isValid(object, func, id, callback) and game:GetService(object) and game:GetService(object)[func]) or false
end
function Hooks:IsValidEvent(object, event, id, callback)
return (isValid(object, event, id, callback) and object[event]) or false
end
function Hooks:RemoveTableEntry(id, hookType)
for _, object in pairs(hookType) do
for _, method in pairs(object) do
for i, _ in pairs(method) do
if i == id then
method[i] = nil
end
end
end
end
end
function Hooks:ConnectHooks(object, func)
game:GetService(object)[func]:Connect(function(...)
for _, v in pairs(self._function_hooks[object][func]) do
warn(typeof(v))
end
end)
end
function Hooks:ConnectEvents(object, event)
object[event]:Connect(function(...)
for _, v in pairs(self._event_hooks[object][event]) do
v(object, ...)
end
end)
end
function Hooks:CheckHooks(object, func)
if self._function_hooks[object] == nil then
self._function_hooks[object] = {}
end
if self._function_hooks[object][func] then
return
end
self._function_hooks[object][func] = {}
self:ConnectHooks(object, func)
end
function Hooks:CheckEvents(object, event)
if self._event_hooks[object] == nil then
self._event_hooks[object] = {}
end
if self._event_hooks[object][event] then
return
end
self._event_hooks[object][event] = {}
Hooks:ConnectEvents(object, event)
end
function Hooks:ExecuteRunServiceHooks(dt)
for _, v in pairs(self._run_service_hooks) do
if v.t > 0 then
v.t -= dt
else
v.callback(dt)
v.t = v.waitTime
end
end
end
Hooks:AddHook("RunService", "Heartbeat", "RunServiceHooks", function(dt)
Hooks:ExecuteRunServiceHooks(dt)
end)
return Hooks
And it’s used by using either AddHook or HookEvent, AddHook is used to hook services, while HookEvent is to hook stuff like Button.MouseButton1Click.
Here’s an example of AddHook:
HooksModule:AddHook("Players", "PlayerRemoving", script.Name .. "PlayerRemoving", function(player)
local playerVoted = Votes._players_voted[player]
if playerVoted then
Votes._maps_voted[playerVoted] -= 1
end
end)
And here’s HookEvent:
local HooksModule = require(game:GetService("ReplicatedStorage").Modules.Hooks)
local currentlyOpened
for _, v in pairs(script.Parent:GetChildren()) do
if v:IsA("Folder") then
HooksModule:HookEvent(v.Button, "MouseButton1Click", script.Name, function(o)
if currentlyOpened and currentlyOpened ~= v.Frame then
currentlyOpened.Visible = false
end
v.Frame.Visible = not v.Frame.Visible
currentlyOpened = v.Frame --Doesn't matter, if it's closed or not. It will be force closed either way.
end)
end
end
Additionally there’s to hook RunService, but I didn’t include it as it pretty much goes to AddHook.