Skip to content

Instantly share code, notes, and snippets.

@NanoAi
Last active August 11, 2017 21:45
Show Gist options
  • Save NanoAi/e354c884ecb2b5aff4a25d20d679db7f to your computer and use it in GitHub Desktop.
Save NanoAi/e354c884ecb2b5aff4a25d20d679db7f to your computer and use it in GitHub Desktop.
A concept for better hooks in Garry's Mod
local f = {} -- f is for hook functions.
local e = {} -- e is for broken hook functions.
local gmod = gmod
local pmv = SortedPairsByMemberValue
local unpack = unpack
local isstring = isstring
local isfunction = isfunction
local IsValid = IsValid
local lhook = hook
local hook = {}
_G.lhook = lhook
_G.hook = hook
function hook.GetTable()
return f
end
function hook.GetErrors()
return e
end
function hook.Add(event, id, callback, priority)
if isstring(event) then
event = {event}
end
for _,key in ipairs(event) do
f[key] = f[key] or {}
f[key][id] = {priority = priority, callback}
end
end
function hook.Inject(event, func, after)
local old = func
if after then
func = function(self, ...)
local re = old(self, ...)
hook.Run(event, re, ...)
return re
end
else
func = function(self, ...)
hook.Run(event, ...)
return old(self, ...)
end
end
return func
end
function hook.Remove(event, id)
if isstring(event) then
event = {event}
end
for _,key in ipairs(event) do
if f[event][id] then
f[event][id] = nil
end
end
end
local function catch(event,id,info)
local stack = debug.traceback(coroutine.running(), info, 2)
local object = f[event] and f[event][id] or nil
if object then
object.errors = object.errors or {}
table.insert(object.errors, stack)
if #f[event][id].errors > 5 then
e[event] = e[event] or {}
e[event][id] = f[event][id]
e[event][id].errors = stack
f[event][id] = nil
end
end
error(stack)
end
local function run(event, gm, ignore_priority, ...)
local re
if f[event] then
if isstring(event) or IsValid(event) then
if ignore_priority then
for id, data in next, f[event] do
re = {xpcall(data.callback,
function(info) catch(event,id,info) end,
...
)}
if re ~= nil then
return unpack(re)
end
end
else
for id, data in pmv(f[event], 'priority') do
re = {xpcall(data.callback,
function(info) catch(event,id,info) end,
...
)}
if re ~= nil then
return unpack(re)
end
end
end
else
f[event][id] = nil
end
end
local GM = GM or GAMEMODE
if GM then
local GamemodeFunction = GM[event]
if isfunction(GamemodeFunction) then
return GamemodeFunction(GM, ...)
end
end
end
function hook.Call(event, gm, ...)
local re = {run(event, gm, false, ...)}
return unpack(re)
end
function hook.Run(event, ...)
local re = {run(event, gmod and gmod.GetGamemode() or nil, false, ...)}
return unpack(re)
end
function hook.RunEx(event, ignore_priority, delay, ...)
local re
local delay = CurTime() + delay
if ( CurTime() > delay ) then
re = {run(event, gmod and gmod.GetGamemode() or nil, ignore_priority, ...)}
return unpack(re)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment