2017-07-23 14:51:20 +02:00
|
|
|
-- Threading simulation module
|
2018-01-27 17:49:55 +02:00
|
|
|
-- Task.sleep()
|
2018-12-22 01:37:00 +02:00
|
|
|
-- @author Valansch and Grilledham
|
2019-02-04 20:07:40 +02:00
|
|
|
-- github: https://github.com/Refactorio/RedMew
|
2017-07-23 14:51:20 +02:00
|
|
|
-- ======================================================= --
|
|
|
|
|
2019-01-04 22:02:16 +02:00
|
|
|
local Queue = require 'utils.queue'
|
2018-11-26 03:07:03 +02:00
|
|
|
local PriorityQueue = require 'utils.priority_queue'
|
2018-05-24 16:16:38 +02:00
|
|
|
local Event = require 'utils.event'
|
2018-11-26 03:07:03 +02:00
|
|
|
local Token = require 'utils.token'
|
2019-02-25 03:04:19 +02:00
|
|
|
local ErrorLogging = require 'utils.error_logging'
|
2019-06-22 23:36:13 +02:00
|
|
|
local Global = require 'utils.global'
|
2017-07-23 14:51:20 +02:00
|
|
|
|
2019-06-22 23:36:13 +02:00
|
|
|
local floor = math.floor
|
|
|
|
local log10 = math.log10
|
|
|
|
local Token_get = Token.get
|
|
|
|
local pcall = pcall
|
|
|
|
local Queue_peek = Queue.peek
|
|
|
|
local Queue_pop = Queue.pop
|
|
|
|
local Queue_push = Queue.push
|
|
|
|
local PriorityQueue_peek = PriorityQueue.peek
|
|
|
|
local PriorityQueue_pop = PriorityQueue.pop
|
|
|
|
local PriorityQueue_push = PriorityQueue.push
|
2017-07-23 14:51:20 +02:00
|
|
|
|
2019-06-22 23:36:13 +02:00
|
|
|
local Task = {}
|
2018-01-31 22:30:32 +02:00
|
|
|
|
2019-06-22 23:36:13 +02:00
|
|
|
local function comparator(a, b)
|
2018-05-24 16:16:38 +02:00
|
|
|
return a.time < b.time
|
2018-01-31 22:30:32 +02:00
|
|
|
end
|
|
|
|
|
2019-06-22 23:36:13 +02:00
|
|
|
local callbacks = PriorityQueue.new(comparator)
|
|
|
|
local task_queue = Queue.new()
|
|
|
|
local primitives = {
|
|
|
|
next_async_callback_time = -1,
|
|
|
|
total_task_weight = 0,
|
|
|
|
task_queue_speed = 1,
|
|
|
|
task_per_tick = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
Global.register(
|
|
|
|
{callbacks = callbacks, task_queue = task_queue, primitives = primitives},
|
|
|
|
function(tbl)
|
|
|
|
callbacks = tbl.callbacks
|
|
|
|
task_queue = tbl.task_queue
|
|
|
|
primitives = tbl.primitives
|
2020-05-29 13:20:49 +02:00
|
|
|
|
|
|
|
PriorityQueue.load(callbacks, comparator)
|
2019-06-22 23:36:13 +02:00
|
|
|
end
|
|
|
|
)
|
|
|
|
|
2019-06-22 23:42:27 +02:00
|
|
|
local function get_task_per_tick(tick)
|
|
|
|
if tick % 300 == 0 then
|
2019-06-22 23:36:13 +02:00
|
|
|
local size = primitives.total_task_weight
|
|
|
|
local task_per_tick = floor(log10(size + 1)) * primitives.task_queue_speed
|
|
|
|
if task_per_tick < 1 then
|
|
|
|
task_per_tick = 1
|
2018-11-06 13:55:52 +02:00
|
|
|
end
|
2019-06-22 23:36:13 +02:00
|
|
|
|
|
|
|
primitives.task_per_tick = task_per_tick
|
|
|
|
return task_per_tick
|
2018-11-06 13:55:52 +02:00
|
|
|
end
|
2019-06-22 23:36:13 +02:00
|
|
|
return primitives.task_per_tick
|
2018-11-06 13:55:52 +02:00
|
|
|
end
|
|
|
|
|
2017-07-23 14:51:20 +02:00
|
|
|
local function on_tick()
|
2019-06-22 23:42:27 +02:00
|
|
|
local tick = game.tick
|
|
|
|
|
|
|
|
for i = 1, get_task_per_tick(tick) do
|
2019-06-22 23:36:13 +02:00
|
|
|
local task = Queue_peek(task_queue)
|
2018-05-24 16:16:38 +02:00
|
|
|
if task ~= nil then
|
|
|
|
-- result is error if not success else result is a boolean for if the task should stay in the queue.
|
2019-06-22 23:36:13 +02:00
|
|
|
local success, result = pcall(Token_get(task.func_token), task.params)
|
2018-05-24 16:16:38 +02:00
|
|
|
if not success then
|
2018-12-22 01:37:00 +02:00
|
|
|
if _DEBUG then
|
|
|
|
error(result)
|
|
|
|
else
|
|
|
|
log(result)
|
2019-02-25 03:04:19 +02:00
|
|
|
ErrorLogging.generate_error_report(result)
|
2018-12-22 01:37:00 +02:00
|
|
|
end
|
2019-06-22 23:36:13 +02:00
|
|
|
Queue_pop(task_queue)
|
|
|
|
primitives.total_task_weight = primitives.total_task_weight - task.weight
|
2018-05-24 16:16:38 +02:00
|
|
|
elseif not result then
|
2019-06-22 23:36:13 +02:00
|
|
|
Queue_pop(task_queue)
|
|
|
|
primitives.total_task_weight = primitives.total_task_weight - task.weight
|
2018-05-24 16:16:38 +02:00
|
|
|
end
|
|
|
|
end
|
2017-10-23 13:24:05 +02:00
|
|
|
end
|
2018-01-31 22:30:32 +02:00
|
|
|
|
2019-06-22 23:36:13 +02:00
|
|
|
local callback = PriorityQueue_peek(callbacks)
|
2019-06-22 23:42:27 +02:00
|
|
|
while callback ~= nil and tick >= callback.time do
|
2019-06-22 23:36:13 +02:00
|
|
|
local success, result = pcall(Token_get(callback.func_token), callback.params)
|
2018-05-24 16:16:38 +02:00
|
|
|
if not success then
|
2018-12-22 01:37:00 +02:00
|
|
|
if _DEBUG then
|
|
|
|
error(result)
|
|
|
|
else
|
|
|
|
log(result)
|
2019-02-25 03:04:19 +02:00
|
|
|
ErrorLogging.generate_error_report(result)
|
2018-12-22 01:37:00 +02:00
|
|
|
end
|
2018-05-24 16:16:38 +02:00
|
|
|
end
|
2019-06-22 23:36:13 +02:00
|
|
|
PriorityQueue_pop(callbacks)
|
|
|
|
callback = PriorityQueue_peek(callbacks)
|
2018-05-24 16:16:38 +02:00
|
|
|
end
|
2017-07-23 14:51:20 +02:00
|
|
|
end
|
|
|
|
|
2019-02-04 20:07:40 +02:00
|
|
|
--- Allows you to set a timer (in ticks) after which the tokened function will be run with params given as an argument
|
2019-02-04 21:39:36 +02:00
|
|
|
-- Cannot be called before init
|
2019-02-04 20:07:40 +02:00
|
|
|
-- @param ticks <number>
|
|
|
|
-- @param func_token <number> a token for a function store via the token system
|
|
|
|
-- @param params <any> the argument to send to the tokened function
|
2018-05-24 16:16:38 +02:00
|
|
|
function Task.set_timeout_in_ticks(ticks, func_token, params)
|
2019-02-18 08:43:59 +02:00
|
|
|
if not game then
|
|
|
|
error('cannot call when game is not available', 2)
|
2019-02-04 23:17:00 +02:00
|
|
|
end
|
2018-05-24 16:16:38 +02:00
|
|
|
local time = game.tick + ticks
|
|
|
|
local callback = {time = time, func_token = func_token, params = params}
|
2019-06-22 23:36:13 +02:00
|
|
|
PriorityQueue_push(callbacks, callback)
|
2017-07-23 14:51:20 +02:00
|
|
|
end
|
|
|
|
|
2019-02-04 20:07:40 +02:00
|
|
|
--- Allows you to set a timer (in seconds) after which the tokened function will be run with params given as an argument
|
2019-02-04 21:39:36 +02:00
|
|
|
-- Cannot be called before init
|
2019-02-04 20:07:40 +02:00
|
|
|
-- @param sec <number>
|
|
|
|
-- @param func_token <number> a token for a function store via the token system
|
|
|
|
-- @param params <any> the argument to send to the tokened function
|
2018-05-24 16:16:38 +02:00
|
|
|
function Task.set_timeout(sec, func_token, params)
|
2019-02-18 08:43:59 +02:00
|
|
|
if not game then
|
|
|
|
error('cannot call when game is not available', 2)
|
2019-02-04 23:17:00 +02:00
|
|
|
end
|
2018-05-24 16:16:38 +02:00
|
|
|
Task.set_timeout_in_ticks(60 * sec, func_token, params)
|
2017-10-06 02:13:56 +02:00
|
|
|
end
|
|
|
|
|
2019-02-04 20:07:40 +02:00
|
|
|
--- Queueing allows you to split up heavy tasks which don't need to be completed in the same tick.
|
|
|
|
-- Queued tasks are generally run 1 per tick. If the queue backs up, more tasks will be processed per tick.
|
|
|
|
-- @param func_token <number> a token for a function stored via the token system
|
|
|
|
-- If this function returns `true` it will run again the next tick, delaying other queued tasks (see weight)
|
|
|
|
-- @param params <any> the argument to send to the tokened function
|
|
|
|
-- @param weight <number> (defaults to 1) weight is the number of ticks a task is expected to take.
|
|
|
|
-- Ex. if the task is expected to repeat multiple times (ie. the function returns true and loops several ticks)
|
2018-05-24 16:16:38 +02:00
|
|
|
function Task.queue_task(func_token, params, weight)
|
|
|
|
weight = weight or 1
|
2019-06-22 23:36:13 +02:00
|
|
|
primitives.total_task_weight = primitives.total_task_weight + weight
|
|
|
|
Queue_push(task_queue, {func_token = func_token, params = params, weight = weight})
|
|
|
|
end
|
|
|
|
|
|
|
|
function Task.get_queue_speed()
|
|
|
|
return primitives.task_queue_speed
|
|
|
|
end
|
|
|
|
|
|
|
|
function Task.set_queue_speed(value)
|
|
|
|
value = value or 1
|
|
|
|
if value < 0 then
|
|
|
|
value = 0
|
|
|
|
end
|
|
|
|
|
|
|
|
primitives.task_queue_speed = value
|
2017-10-06 02:13:56 +02:00
|
|
|
end
|
|
|
|
|
2018-04-06 21:58:50 +02:00
|
|
|
Event.add(defines.events.on_tick, on_tick)
|
2017-07-23 14:51:20 +02:00
|
|
|
|
2018-01-27 17:49:55 +02:00
|
|
|
return Task
|