Last active
August 11, 2017 21:45
-
-
Save NanoAi/e354c884ecb2b5aff4a25d20d679db7f to your computer and use it in GitHub Desktop.
A concept for better hooks in Garry's Mod
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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