Skip to content

Instantly share code, notes, and snippets.

@meepen
Last active January 2, 2022 13:55
Show Gist options
  • Save meepen/5566c9598e0e610e5885d12fad2ec3a8 to your computer and use it in GitHub Desktop.
Save meepen/5566c9598e0e610e5885d12fad2ec3a8 to your computer and use it in GitHub Desktop.
NEW GMOD HOOKS 70,000% FASTER - new LINKED LIST version available now for purchase (FREE PRIORITIZATION INCLUDED)
hook = include "newhook.lua"
-- major features of the hook library need to be considered
-- performance is eaten from in-engine hook.Call calls every few frames/ticks
-- add/remove are not super important but should be considered still
local hook_name = "HookSuite"
local call_count = 2000000000
local no_hook_call_count = 2000000000
local invalid_call_count = 20000
local slow = true
if (slow) then
call_count = 32000000
no_hook_call_count = 200000000
invalid_call_count = 200
end
local hooks = {
function()
end,
function()
end,
function()
end
}
local gm = {
[hook_name] = function() end,
NEVERUSETHISOK = function() end
}
return {
CallNoGM = function(lib)
local call = lib.Call
local bench_time, hook_name, call_count = SysTime, hook_name, call_count -- yes this is important
local start_time = bench_time()
for i = 1, call_count do
call(hook_name)
end
local end_time = bench_time()
return (end_time - start_time), call_count
end,
CallGM = function(lib)
local call = lib.Call
local bench_time, hook_name, call_count, gm = SysTime, hook_name, call_count, gm -- yes this is important
local start_time = bench_time()
for i = 1, call_count do
call(hook_name, gm)
end
local end_time = bench_time()
return (end_time - start_time), call_count
end,
CallNoHooks = function(lib)
local call = lib.Call
local bench_time, hook_name, no_hook_call_count = SysTime, "NEVERUSETHISOK", no_hook_call_count -- yes this is important
local start_time = bench_time()
for i = 1, no_hook_call_count do
call(hook_name)
end
local end_time = bench_time()
return (end_time - start_time), no_hook_call_count
end,
CallGMOnly = function(lib)
local call = lib.Call
local bench_time, hook_name, no_hook_call_count = SysTime, "NEVERUSETHISOK", no_hook_call_count -- yes this is important
local start_time = bench_time()
for i = 1, no_hook_call_count do
call(hook_name, gm)
end
local end_time = bench_time()
return (end_time - start_time), no_hook_call_count
end,
CallInvalid = function(lib)
local call, add = lib.Call, lib.Add
local bench_time, hook_name, invalid_call_count = SysTime, "NEVERUSETHISOKENTS", invalid_call_count -- yes this is important
local function nop() end
local total_time = 0
local invalid = {}
local valid = {}
for i = 1, 25 do
invalid[i] = {IsValid = function() return false end}
valid[i] = {IsValid = function() return true end}
end
for i = 1, invalid_call_count do
for i2 = 1, 25 do -- very extreme case
add(hook_name, invalid[i2], nop)
add(hook_name, valid[i2], nop)
end
local start_time = bench_time()
call(hook_name)
local end_time = bench_time()
total_time = total_time + (end_time - start_time)
end
return total_time, invalid_call_count
end,
Verify = function(hook)
local HOOK_ID = "VERIFY_HOOK"
local call_count = 0
local function add() call_count = call_count + 1 end
hook.Add(HOOK_ID, HOOK_ID, add)
hook.Call(HOOK_ID)
assert(call_count == 1, "Call count not sane")
call_count = 0
hook.Remove(HOOK_ID, HOOK_ID)
hook.Call(HOOK_ID)
assert(call_count == 0, "Call count not sane after remove")
call_count = 0
hook.Add(HOOK_ID, HOOK_ID, add)
hook.Call(HOOK_ID)
assert(call_count == 1, "Call count not sane after readd")
call_count = 0
hook.Add(HOOK_ID, HOOK_ID, add)
hook.Call(HOOK_ID)
assert(call_count == 1, "Call count not sane after duped add")
call_count = 0
local t = {IsValid = function() return true end}
hook.Add(HOOK_ID, t, add)
hook.Call(HOOK_ID)
assert(call_count == 2, "Call count not sane after calling IsValid")
hook.Add(HOOK_ID, HOOK_ID)
assert(hook.GetTable()[HOOK_ID][HOOK_ID], "Removed instead of returning")
call_count = 0
hook.Call(HOOK_ID)
assert(call_count == 2, "Wrong call count after add with nil function")
hook.Remove(HOOK_ID, HOOK_ID)
call_count = 0
hook.Call(HOOK_ID)
assert(call_count == 1, "Call count not one")
hook.Remove(HOOK_ID, t)
call_count = 0
hook.Call(HOOK_ID)
assert(call_count == 0, "Call count not zero")
call_count = 0
hook.Add(HOOK_ID, HOOK_ID, add)
t = {IsValid = function() return true end}
hook.Add(HOOK_ID, t, add)
hook.Add(HOOK_ID, {IsValid = function() return false end}, add)
hook.Call(HOOK_ID)
assert(call_count == 2, "Call count not two after adding isvalids "..call_count)
call_count = 0
hook.Remove(HOOK_ID, HOOK_ID)
hook.Add(HOOK_ID, {IsValid = function() return false end}, add)
hook.Add(HOOK_ID, t, add)
hook.Call(HOOK_ID)
assert(call_count == 1, "Call count not one after adding isvalids "..call_count)
call_count = 0
hook.Add(HOOK_ID, {IsValid = function() return false end}, add)
hook.Call(HOOK_ID)
assert(call_count == 1, "Call count not one after adding invalid at end "..call_count)
call_count = 0
hook.Call(HOOK_ID)
assert(call_count == 1, "Call count not one after removing invalid at end"..call_count)
call_count = 0
hook.Add(HOOK_ID, t, add)
hook.Add(HOOK_ID, HOOK_ID)
hook.Remove(HOOK_ID, HOOK_ID)
hook.Call(HOOK_ID)
assert(call_count == 1, "Call count not one after instantly removing "..call_count)
return 0, 1, true
end,
All = function(self, lib)
for i = 1, #hooks do
lib.Add(hook_name, tostring(i), hooks[i])
end
local rets = {}
for k,v in pairs(self) do
if (k ~= "All") then
local time, amountofcalls, success = self[k](lib)
rets[k] = {
Time = time,
Calls = amountofcalls,
Success = success
}
end
end
-- run verify again to make sure nothing broke while doing benches
self.Verify(lib)
return rets
end
}
local file1, file2 = "linkedhooks.lua", "dashhook.lua"
print("testing "..file1)
local score1 = include "hooksuite.lua":All(include(file1))
print("testing "..file2)
local score2 = include "hooksuite.lua":All(include(file2))
print "\n\n\n\n\n\n\n\n"
print "BENCHMARK"
local printafter1 = (" "):rep(math.max(file1:len(), file2:len()) - file1:len())
local printafter2 = (" "):rep(math.max(file1:len(), file2:len()) - file2:len())
for k, v in pairs(score2) do
if (not v.Time) then continue end
local did2win = score1[k].Time > v.Time
print "-------------"
print(string.format("%s (%i calls)\n%s (%.02f%%)", k, v.Calls or 0, did2win and file2 or file1, 100 * (1 - (did2win and score1[k].Time / v.Time or v.Time / score1[k].Time))))
print(string.format("%s:%s %.09f s", file2, printafter2, v.Time))
print(string.format("%s:%s %.09f s", file1, printafter1, score1[k].Time))
end
print "-------------"
if (SERVER and not MENU_DLL) then
AddCSLuaFile()
end
--[[
local i_fn = 1
local i_id = 2
local i_next = 3
local i_real_fn = 4
local i_last = 5
local i_priority = 6
]]
local event_table = {}
local function GetTable()
local out = {}
for event, hooklist in pairs(event_table) do
out[event] = {}
::startloop::
out[event][hooklist[2 --[[i_id]]]] = hooklist[4 --[[i_real_fn]]]
hooklist = hooklist[3 --[[i_next]]]
if (hooklist) then
goto startloop
end
end
return out
end
local function Remove(event, name)
if (not name) then
return
end
local hook = event_table[event]
if (not hook) then
return
end
local found = false
local event_start = hook
::startloop::
if (hook[2 --[[i_id]]] == name) then
if (hook == event_start) then
event_table[event] = hook[3 --[[i_next]]]
end
local last, next = hook[5 --[[i_last]]], hook[3 --[[i_next]]]
if (last) then
last[3 --[[i_next]]] = hook[3 --[[i_next]]]
end
if (next) then
next[5 --[[i_last]]] = hook[5 --[[i_last]]]
end
found = true
goto breakloop
end
hook = hook[3 --[[i_next]]]
if (hook) then
goto startloop
end
::breakloop::
if (not found) then
return
end
local start = event_table[event]
if (not start) then
return
end
end
local function Add(event, name, fn, priority)
assert(event ~= nil, "bad argument #1 to 'Add' (value expected)")
if (not name or not fn) then
return
end
local real_fn = fn
if (type(name) ~= "string") then
fn = function(...)
if (IsValid(name)) then
local a, b, c, d, e, f = real_fn(name, ...)
if (a ~= nil) then
return a, b, c, d, e, f
end
return
end
Remove(event, name)
end
end
local hook = event_table[event]
local new_hook
local found = false
if (hook) then
::startloop::
if (hook[2 --[[i_id]]] == name) then
new_hook = hook
found = true
goto breakloop
end
hook = hook[3 --[[i_next]]]
if (hook) then
goto startloop
end
end
::breakloop::
if (not priority) then
priority = 0
end
if (found) then
new_hook[1 --[[i_fn]] ] = fn
new_hook[4 --[[i_real_fn]]] = real_fn
if (new_hook[6 --[[i_priority]]] == priority) then
return
end
-- WARNING: UNDEFINED BEHAVIOR WARNING doing this inside another hook with earlier priority than the hook running WILL run the hook again
Remove(event, name)
new_hook[6 --[[i_priority]]] = priority
new_hook[3 --[[i_next]]] = nil
new_hook[5 --[[i_last]]] = nil
else
new_hook = {
-- i_fn
fn,
-- i_id
name,
-- i_next
nil,
-- i_real_fn
real_fn,
-- i_last
nil,
-- i_priority
priority
}
end
-- find link in hook list to add to
hook = event_table[event]
local event_start = hook
if (hook) then
local lasthook
::startloop2::
if (hook[6 --[[i_priority]]] <= priority) then
if (lasthook) then
lasthook[3 --[[i_next]]] = new_hook
end
hook[5 --[[i_last]]] = new_hook
new_hook[3 --[[i_next]]] = hook
new_hook[5 --[[i_last]]] = lasthook
if (event_start ~= hook) then
return
end
goto breakloop2
end
lasthook = hook
hook = hook[3 --[[i_next]]]
if (hook) then
goto startloop2
else
-- NOT SUITABLE IN TABLE, update at end
lasthook[3 --[[i_next]]] = new_hook
return
end
end
::breakloop2::
event_table[event] = new_hook
end
local function Call(event, gm, ...)
-- TODO: hooks
local hook = event_table[event]
if (hook) then
::startloop::
local a, b, c, d, e, f = hook[1 --[[i_fn]]](...)
if (a ~= nil) then
return a, b, c, d, e, f
end
hook = hook[3 --[[i_next]]]
if (hook) then
goto startloop
end
end
if (gm) then
local fn = gm[event]
if (fn) then
return fn(gm, ...)
end
end
end
local gmod = gmod
local function Run(event, ...)
return Call(event, gmod and gmod.GetGamemode() or nil, ...)
end
return {
Remove = Remove,
GetTable = GetTable,
Add = Add,
Call = Call,
Run = Run,
Priority = {
NO_RETURN = math.huge -- not enforced, just should be followed
}
}
@TrixterTheTux
Copy link

leaked

@ThatLing
Copy link

this devalues my fps optimizer script that removes all hooks

@xbeastguyx
Copy link

you made my darkrp 4k

@moonexpr
Copy link

my gmod server can run on my toaster now

@oubliette32
Copy link

does this work with darkrp 2.4?

@Lunaversitay
Copy link

securegmod broke

@anyome
Copy link

anyome commented Jan 2, 2020

How to install this? i did put it on : lua/autorun/server but doesn't works !
HELP PLZ i need more fps on my darkrp server

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment