94 lines
3.2 KiB
Lua
94 lines
3.2 KiB
Lua
-- Timedpairs by Grocel. (Rewrite by Divran)
|
|
-- It allows you to go through long tables, but without game freezing.
|
|
-- Its like a for-pairs loop.
|
|
--
|
|
-- How to use:
|
|
-- WireLib.Timedpairs(string unique name, table, number ticks done at once, function tickcallback[, function endcallback, ...])
|
|
--
|
|
-- tickcallback is called every tick, it ticks for each KeyValue of the table.
|
|
-- Its arguments are the current key and value.
|
|
-- Return false in the tickcallback function to break the loop.
|
|
-- tickcallback(key, value, ...)
|
|
--
|
|
-- endcallback is called after the last tickcallback has been called.
|
|
-- Its arguments are the same as the last arguments of WireLib.Timedpairs
|
|
-- endcallback(lastkey, lastvalue, ...)
|
|
|
|
if (!WireLib) then return end
|
|
|
|
local next = next
|
|
local pairs = pairs
|
|
local unpack = unpack
|
|
local pcall = pcall
|
|
|
|
local functions = {}
|
|
function WireLib.TimedpairsGetTable()
|
|
return functions
|
|
end
|
|
|
|
function WireLib.TimedpairsStop(name)
|
|
functions[name] = nil
|
|
end
|
|
|
|
local function copy( t ) -- custom table copy function to convert to numerically indexed table
|
|
local ret = {}
|
|
for k,v in pairs( t ) do
|
|
ret[#ret+1] = { key = k, value = v }
|
|
end
|
|
return ret
|
|
end
|
|
|
|
local function Timedpairs()
|
|
if not next(functions) then return end
|
|
|
|
local toremove = {}
|
|
|
|
for name, data in pairs( functions ) do
|
|
for i=1,data.step do
|
|
data.currentindex = data.currentindex + 1 -- increment index counter
|
|
local lookup = data.lookup or {}
|
|
if data.currentindex <= #lookup then -- If there are any more values..
|
|
local kv = lookup[data.currentindex] or {} -- Get the current key and value
|
|
local ok, err = xpcall( data.callback, debug.traceback, kv.key, kv.value, unpack(data.args) ) -- DO EET
|
|
|
|
if not ok then -- oh noes
|
|
WireLib.ErrorNoHalt( "Error in Timedpairs '" .. name .. "': " .. err )
|
|
toremove[#toremove+1] = name
|
|
break
|
|
elseif err == false then -- They returned false inside the function
|
|
toremove[#toremove+1] = name
|
|
break
|
|
end
|
|
else -- Out of keys. Entire table looped
|
|
if data.endcallback then -- If we had any end callback function
|
|
local kv = lookup[data.currentindex-1] or {} -- get previous key & value
|
|
local ok, err = xpcall( data.endcallback, debug.traceback, kv.key, kv.value, unpack(data.args) )
|
|
|
|
if not ok then
|
|
WireLib.ErrorNoHalt( "Error in Timedpairs '" .. name .. "' (in end function): " .. err )
|
|
end
|
|
end
|
|
toremove[#toremove+1] = name
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
for i=1,#toremove do -- Remove all that were flagged for removal
|
|
functions[toremove[i]] = nil
|
|
end
|
|
end
|
|
if (CLIENT) then
|
|
hook.Add("PostRenderVGUI", "WireLib_Timedpairs", Timedpairs) // Doesn't get paused in single player. Can be important for vguis.
|
|
else
|
|
hook.Add("Think", "WireLib_Timedpairs", Timedpairs) // Servers still uses Think.
|
|
end
|
|
|
|
function WireLib.Timedpairs(name,tab,step,callback,endcallback,...)
|
|
functions[name] = { lookup = copy(tab), step = step, currentindex = 0, callback = callback, endcallback = endcallback, args = {...} }
|
|
end
|
|
|
|
function WireLib.Timedcall(callback,...) // calls the given function like simple timer, but isn't affected by game pausing.
|
|
local dummytab = {true}
|
|
WireLib.Timedpairs("Timedcall_"..tostring(dummytab),dummytab,1,function(k, v, ...) callback(...) end,nil,...)
|
|
end
|