Divergent/mods/Arrival/gamedata/scripts/demonized_concurrent_queues...

102 lines
2.8 KiB
Plaintext

local table_remove = table.remove
local unpack = unpack
local function table_keys(t, is_array)
local a = {}
if is_array then
for i = 1, #t do
a[i] = i
end
else
for k,v in pairs(t) do
a[#a+1] = k
end
end
return a
end
-- Queue to span processing on each game tick
-- Arguments:
-- queue_name - name of queue
-- queue_table - table to process
-- func - function for processing, must have at least first 3 arguments: key of queue_table, value by that key, the number of key in processing order
-- returning true will remove element from queue, returning false or nil will leave it in queue for next process cycle
-- on_end_func - function at the end of queue processing, you can use this for chaining queue processing one after another
-- step - amount of items in queue to process at a time
-- ... - additional arguments for "func"
-- active_queues table contains names of queues that are active.
-- Example usage, get an object by id one at a time per game update
--[[
local ids = {1, 2, 3, 4, 5, 6, 7, 8}
process_queue("my_queue", ids, function(k, id, i)
local obj = level.object_by_id(id)
if obj then
printf("object %s, section %s, time_global %s", id, obj:section(), time_global())
end
return true
end, function()
printf("queue processed, final time %s", time_global())
end
)
]]
active_queues = {}
function process_queue(queue_name, queue_table, func, on_end_func, step, ...)
-- queue_table must be a table
if not queue_table or type(queue_table) ~= "table" then
printf("%s is not table, abort", queue_table)
return
end
if active_queues[queue_name] then
printf("queue %s is already active, abort", queue_name)
return
end
-- Collect table keys and initialize the table index
local i = 1
local keys = table_keys(queue_table)
local step = clamp(step or 1, 1, #keys)
local args = {...}
local update_func
update_func = function()
for s = 1, step do
local j = keys[i]
if func(j, queue_table[j], i, unpack(args)) == true then
queue_table[j] = nil
table_remove(keys, i)
i = i - 1
step = clamp(step, 1, #keys)
end
if not keys[1] then
if on_end_func then on_end_func() end
UnregisterScriptCallback("actor_on_update", update_func)
active_queues[queue_name] = nil
return
end
i = i == #keys and 1 or i + 1
end
end
active_queues[queue_name] = {
queue_table = queue_table,
func = update_func,
on_end_func = on_end_func,
step = step,
}
RegisterScriptCallback("actor_on_update", update_func)
end
function remove_queue(queue_name, on_end)
if active_queues[queue_name] then
if on_end and active_queues[queue_name].on_end_func then
active_queues[queue_name].on_end_func()
end
UnregisterScriptCallback("actor_on_update", active_queues[queue_name].func)
active_queues[queue_name] = nil
end
end