SuperiorServers / dash

Collection of libraries, utilities, and core Garry's Mod changes intended to improve development of addons and gamemodes
Other
66 stars 20 forks source link

Fix hook.Remove being called in a hook breaking later hooks #17

Closed swampservers closed 1 year ago

swampservers commented 1 year ago

If you do code like:

hook.Add("Tick", "ThingToDoNextTick", function()
    print("Joker Gaming")
    hook.Remove("Tick", "ThingToDoNextTick")
end)

This would work in vanilla hooks because iterate-and-remove works with pairs(). But it does not work with this hook library because removing the hook causes the last hook in the sequence to be swapped into its place, then that previous last hook will be skipped by the iteration.

The fix makes hook.Remove put a temporary "gap function" where the removed hook used to be which will be swapped on the next call of the hook (it only does this if there are later hooks). The gap functions are denoted by the lack of an id being mapped to their index.

Code to test it: (output is wrong before change)

local calls, frame = 0, 0
for i=1, 100 do
    local n = "hook"..i
    hook.Add("Tick", n, function()
        if frame ~= engine.TickCount() then
            frame = engine.TickCount()
            calls = 0
        end
        calls = calls + 1
        hook.Remove("Tick", n)
    end)
end
timer.Simple(0.1, function() print("calls", calls) end)

Other changes: