mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 11:35:22 +09:00
Move files to exp_legacy
This commit is contained in:
147
exp_legacy/module/utils/color_presets.lua
Normal file
147
exp_legacy/module/utils/color_presets.lua
Normal file
@@ -0,0 +1,147 @@
|
||||
-- source: https://www.rapidtables.com/web/color/RGB_Color.html
|
||||
return {
|
||||
maroon = {r = 128, g = 0, b = 0},
|
||||
dark_red = {r = 139, g = 0, b = 0},
|
||||
brown = {r = 165, g = 42, b = 42},
|
||||
firebrick = {r = 178, g = 34, b = 34},
|
||||
crimson = {r = 220, g = 20, b = 60},
|
||||
red = {r = 255, g = 0, b = 0},
|
||||
tomato = {r = 255, g = 99, b = 71},
|
||||
coral = {r = 255, g = 127, b = 80},
|
||||
indian_red = {r = 205, g = 92, b = 92},
|
||||
light_coral = {r = 240, g = 128, b = 128},
|
||||
dark_salmon = {r = 233, g = 150, b = 122},
|
||||
salmon = {r = 250, g = 128, b = 114},
|
||||
light_salmon = {r = 255, g = 160, b = 122},
|
||||
orange_red = {r = 255, g = 69, b = 0},
|
||||
dark_orange = {r = 255, g = 140, b = 0},
|
||||
orange = {r = 255, g = 165, b = 0},
|
||||
gold = {r = 255, g = 215, b = 0},
|
||||
dark_golden_rod = {r = 184, g = 134, b = 11},
|
||||
golden_rod = {r = 218, g = 165, b = 32},
|
||||
pale_golden_rod = {r = 238, g = 232, b = 170},
|
||||
dark_khaki = {r = 189, g = 183, b = 107},
|
||||
khaki = {r = 240, g = 230, b = 140},
|
||||
olive = {r = 128, g = 128, b = 0},
|
||||
yellow = {r = 255, g = 255, b = 0},
|
||||
yellow_green = {r = 154, g = 205, b = 50},
|
||||
dark_olive_green = {r = 85, g = 107, b = 47},
|
||||
olive_drab = {r = 107, g = 142, b = 35},
|
||||
lawn_green = {r = 124, g = 252, b = 0},
|
||||
chart_reuse = {r = 127, g = 255, b = 0},
|
||||
green_yellow = {r = 173, g = 255, b = 47},
|
||||
dark_green = {r = 0, g = 100, b = 0},
|
||||
green = {r = 0, g = 128, b = 0},
|
||||
forest_green = {r = 34, g = 139, b = 34},
|
||||
lime = {r = 0, g = 255, b = 0},
|
||||
lime_green = {r = 50, g = 205, b = 50},
|
||||
light_green = {r = 144, g = 238, b = 144},
|
||||
pale_green = {r = 152, g = 251, b = 152},
|
||||
dark_sea_green = {r = 143, g = 188, b = 143},
|
||||
medium_spring_green = {r = 0, g = 250, b = 154},
|
||||
spring_green = {r = 0, g = 255, b = 127},
|
||||
sea_green = {r = 46, g = 139, b = 87},
|
||||
medium_aqua_marine = {r = 102, g = 205, b = 170},
|
||||
medium_sea_green = {r = 60, g = 179, b = 113},
|
||||
light_sea_green = {r = 32, g = 178, b = 170},
|
||||
dark_slate_gray = {r = 47, g = 79, b = 79},
|
||||
teal = {r = 0, g = 128, b = 128},
|
||||
dark_cyan = {r = 0, g = 139, b = 139},
|
||||
aqua = {r = 0, g = 255, b = 255},
|
||||
cyan = {r = 0, g = 255, b = 255},
|
||||
light_cyan = {r = 224, g = 255, b = 255},
|
||||
dark_turquoise = {r = 0, g = 206, b = 209},
|
||||
turquoise = {r = 64, g = 224, b = 208},
|
||||
medium_turquoise = {r = 72, g = 209, b = 204},
|
||||
pale_turquoise = {r = 175, g = 238, b = 238},
|
||||
aqua_marine = {r = 127, g = 255, b = 212},
|
||||
powder_blue = {r = 176, g = 224, b = 230},
|
||||
cadet_blue = {r = 95, g = 158, b = 160},
|
||||
steel_blue = {r = 70, g = 130, b = 180},
|
||||
corn_flower_blue = {r = 100, g = 149, b = 237},
|
||||
deep_sky_blue = {r = 0, g = 191, b = 255},
|
||||
dodger_blue = {r = 30, g = 144, b = 255},
|
||||
light_blue = {r = 173, g = 216, b = 230},
|
||||
sky_blue = {r = 135, g = 206, b = 235},
|
||||
light_sky_blue = {r = 135, g = 206, b = 250},
|
||||
midnight_blue = {r = 25, g = 25, b = 112},
|
||||
navy = {r = 0, g = 0, b = 128},
|
||||
dark_blue = {r = 0, g = 0, b = 139},
|
||||
medium_blue = {r = 0, g = 0, b = 205},
|
||||
blue = {r = 0, g = 0, b = 255},
|
||||
royal_blue = {r = 65, g = 105, b = 225},
|
||||
blue_violet = {r = 138, g = 43, b = 226},
|
||||
indigo = {r = 75, g = 0, b = 130},
|
||||
dark_slate_blue = {r = 72, g = 61, b = 139},
|
||||
slate_blue = {r = 106, g = 90, b = 205},
|
||||
medium_slate_blue = {r = 123, g = 104, b = 238},
|
||||
medium_purple = {r = 147, g = 112, b = 219},
|
||||
dark_magenta = {r = 139, g = 0, b = 139},
|
||||
dark_violet = {r = 148, g = 0, b = 211},
|
||||
dark_orchid = {r = 153, g = 50, b = 204},
|
||||
medium_orchid = {r = 186, g = 85, b = 211},
|
||||
purple = {r = 128, g = 0, b = 128},
|
||||
thistle = {r = 216, g = 191, b = 216},
|
||||
plum = {r = 221, g = 160, b = 221},
|
||||
violet = {r = 238, g = 130, b = 238},
|
||||
magenta = {r = 255, g = 0, b = 255},
|
||||
fuchsia = {r = 255, g = 0, b = 255},
|
||||
orchid = {r = 218, g = 112, b = 214},
|
||||
medium_violet_red = {r = 199, g = 21, b = 133},
|
||||
pale_violet_red = {r = 219, g = 112, b = 147},
|
||||
deep_pink = {r = 255, g = 20, b = 147},
|
||||
hot_pink = {r = 255, g = 105, b = 180},
|
||||
light_pink = {r = 255, g = 182, b = 193},
|
||||
pink = {r = 255, g = 192, b = 203},
|
||||
antique_white = {r = 250, g = 235, b = 215},
|
||||
beige = {r = 245, g = 245, b = 220},
|
||||
bisque = {r = 255, g = 228, b = 196},
|
||||
blanched_almond = {r = 255, g = 235, b = 205},
|
||||
wheat = {r = 245, g = 222, b = 179},
|
||||
corn_silk = {r = 255, g = 248, b = 220},
|
||||
lemon_chiffon = {r = 255, g = 250, b = 205},
|
||||
light_golden_rod_yellow = {r = 250, g = 250, b = 210},
|
||||
light_yellow = {r = 255, g = 255, b = 224},
|
||||
saddle_brown = {r = 139, g = 69, b = 19},
|
||||
sienna = {r = 160, g = 82, b = 45},
|
||||
chocolate = {r = 210, g = 105, b = 30},
|
||||
peru = {r = 205, g = 133, b = 63},
|
||||
sandy_brown = {r = 244, g = 164, b = 96},
|
||||
burly_wood = {r = 222, g = 184, b = 135},
|
||||
tan = {r = 210, g = 180, b = 140},
|
||||
rosy_brown = {r = 188, g = 143, b = 143},
|
||||
moccasin = {r = 255, g = 228, b = 181},
|
||||
navajo_white = {r = 255, g = 222, b = 173},
|
||||
peach_puff = {r = 255, g = 218, b = 185},
|
||||
misty_rose = {r = 255, g = 228, b = 225},
|
||||
lavender_blush = {r = 255, g = 240, b = 245},
|
||||
linen = {r = 250, g = 240, b = 230},
|
||||
old_lace = {r = 253, g = 245, b = 230},
|
||||
papaya_whip = {r = 255, g = 239, b = 213},
|
||||
sea_shell = {r = 255, g = 245, b = 238},
|
||||
mint_cream = {r = 245, g = 255, b = 250},
|
||||
slate_gray = {r = 112, g = 128, b = 144},
|
||||
light_slate_gray = {r = 119, g = 136, b = 153},
|
||||
light_steel_blue = {r = 176, g = 196, b = 222},
|
||||
lavender = {r = 230, g = 230, b = 250},
|
||||
floral_white = {r = 255, g = 250, b = 240},
|
||||
alice_blue = {r = 240, g = 248, b = 255},
|
||||
ghost_white = {r = 248, g = 248, b = 255},
|
||||
honeydew = {r = 240, g = 255, b = 240},
|
||||
ivory = {r = 255, g = 255, b = 240},
|
||||
azure = {r = 240, g = 255, b = 255},
|
||||
snow = {r = 255, g = 250, b = 250},
|
||||
black = {r = 0, g = 0, b = 0},
|
||||
silver = {r = 192, g = 192, b = 192},
|
||||
dim_grey = {r = 105, g = 105, b = 105},
|
||||
grey = {r = 128, g = 128, b = 128},
|
||||
dark_grey = {r = 169, g = 169, b = 169},
|
||||
light_grey = {r = 211, g = 211, b = 211},
|
||||
gainsboro = {r = 220, g = 220, b = 220},
|
||||
white_smoke = {r = 245, g = 245, b = 245},
|
||||
white = {r = 255, g = 255, b = 255},
|
||||
success = {r = 0, g = 255, b = 0},
|
||||
warning = {r = 255, g = 255, b = 0},
|
||||
fail = {r = 255, g = 0, b = 0},
|
||||
info = {r = 255, g = 255, b = 255}
|
||||
}
|
||||
457
exp_legacy/module/utils/event.lua
Normal file
457
exp_legacy/module/utils/event.lua
Normal file
@@ -0,0 +1,457 @@
|
||||
--- This Module allows for registering multiple handlers to the same event, overcoming the limitation of script.register.
|
||||
--
|
||||
-- ** Event.add(event_name, handler) **
|
||||
--
|
||||
-- Handlers added with Event.add must be added at the control stage or in Event.on_init or Event.on_load.
|
||||
-- Remember that for each player, on_init or on_load is run, never both. So if you can't add the handler in the
|
||||
-- control stage add the handler in both on_init and on_load.
|
||||
-- Handlers added with Event.add cannot be removed.
|
||||
-- For handlers that need to be removed or added at runtime use Event.add_removable.
|
||||
-- @usage
|
||||
-- local Event = require 'utils.event' --- @dep utils.event
|
||||
-- Event.add(
|
||||
-- defines.events.on_built_entity,
|
||||
-- function(event)
|
||||
-- game.print(serpent.block(event)) -- prints the content of the event table to console.
|
||||
-- end
|
||||
-- )
|
||||
--
|
||||
-- ** Event.add_removable(event_name, token) **
|
||||
--
|
||||
-- For conditional event handlers. Event.add_removable can be safely called at runtime without desync risk.
|
||||
-- Only use this if you need to add the handler at runtime or need to remove the handler, otherwise use Event.add
|
||||
--
|
||||
-- Event.add_removable can be safely used at the control stage or in Event.on_init. If used in on_init you don't
|
||||
-- need to also add in on_load (unlike Event.add).
|
||||
-- Event.add_removable cannot be called in on_load, doing so will crash the game on loading.
|
||||
-- Token is used because it's a desync risk to store closures inside the global table.
|
||||
--
|
||||
-- @usage
|
||||
-- local Token = require 'utils.token' --- @dep utils.token
|
||||
-- local Event = require 'utils.event' --- @dep utils.event
|
||||
--
|
||||
-- Token.register must not be called inside an event handler.
|
||||
-- local handler =
|
||||
-- Token.register(
|
||||
-- function(event)
|
||||
-- game.print(serpent.block(event)) -- prints the content of the event table to console.
|
||||
-- end
|
||||
-- )
|
||||
--
|
||||
-- The below code would typically be inside another event or a custom command.
|
||||
-- Event.add_removable(defines.events.on_built_entity, handler)
|
||||
--
|
||||
-- When you no longer need the handler.
|
||||
-- Event.remove_removable(defines.events.on_built_entity, handler)
|
||||
--
|
||||
-- It's not an error to register the same token multiple times to the same event, however when
|
||||
-- removing only the first occurrence is removed.
|
||||
--
|
||||
-- ** Event.add_removable_function(event_name, func) **
|
||||
--
|
||||
-- Only use this function if you can't use Event.add_removable. i.e you are registering the handler at the console.
|
||||
-- The same restrictions that apply to Event.add_removable also apply to Event.add_removable_function.
|
||||
-- func cannot be a closure in this case, as there is no safe way to store closures in the global table.
|
||||
-- A closure is a function that uses a local variable not defined in the function.
|
||||
--
|
||||
-- @usage
|
||||
-- local Event = require 'utils.event' --- @dep utils.event
|
||||
--
|
||||
-- If you want to remove the handler you will need to keep a reference to it.
|
||||
-- global.handler = function(event)
|
||||
-- game.print(serpent.block(event)) -- prints the content of the event table to console.
|
||||
-- end
|
||||
--
|
||||
-- The below code would typically be used at the command console.
|
||||
-- Event.add_removable_function(defines.events.on_built_entity, global.handler)
|
||||
--
|
||||
-- When you no longer need the handler.
|
||||
-- Event.remove_removable_function(defines.events.on_built_entity, global.handler)
|
||||
--
|
||||
-- ** Other Events **
|
||||
--
|
||||
-- Use Event.on_init(handler) for script.on_init(handler)
|
||||
-- Use Event.on_load(handler) for script.on_load(handler)
|
||||
--
|
||||
-- Use Event.on_nth_tick(tick, handler) for script.on_nth_tick(tick, handler)
|
||||
-- Favour this event over Event.add(defines.events.on_tick, handler)
|
||||
-- There are also Event.add_removable_nth_tick(tick, token) and Event.add_removable_nth_tick_function(tick, func)
|
||||
-- That work the same as above.
|
||||
--
|
||||
-- ** Custom Scenario Events **
|
||||
--
|
||||
-- local Event = require 'utils.event' --- @dep utils.event
|
||||
--
|
||||
-- local event_id = script.generate_event_name()
|
||||
--
|
||||
-- Event.add(
|
||||
-- event_id,
|
||||
-- function(event)
|
||||
-- game.print(serpent.block(event)) -- prints the content of the event table to console.
|
||||
-- end
|
||||
-- )
|
||||
--
|
||||
-- The table contains extra information that you want to pass to the handler.
|
||||
-- script.raise_event(event_id, {extra = 'data'})
|
||||
|
||||
local EventCore = require 'utils.event_core' --- @dep utils.event_core
|
||||
local Global = require 'utils.global' --- @dep utils.global
|
||||
local Token = require 'utils.token' --- @dep utils.token
|
||||
local Debug = require 'overrides.debug' --- @dep overrides.debug
|
||||
|
||||
local table_remove = table.remove
|
||||
local core_add = EventCore.add
|
||||
local core_on_init = EventCore.on_init
|
||||
local core_on_load = EventCore.on_load
|
||||
local core_on_nth_tick = EventCore.on_nth_tick
|
||||
local stage_load = _STAGE.load
|
||||
local script_on_event = script.on_event
|
||||
local script_on_nth_tick = script.on_nth_tick
|
||||
|
||||
local Event = {}
|
||||
|
||||
local handlers_added = false -- set to true after the removeable event handlers have been added.
|
||||
|
||||
local event_handlers = EventCore.get_event_handlers()
|
||||
local on_nth_tick_event_handlers = EventCore.get_on_nth_tick_event_handlers()
|
||||
|
||||
local token_handlers = {}
|
||||
local token_nth_tick_handlers = {}
|
||||
local function_handlers = {}
|
||||
local function_nth_tick_handlers = {}
|
||||
|
||||
Global.register(
|
||||
{
|
||||
token_handlers = token_handlers,
|
||||
token_nth_tick_handlers = token_nth_tick_handlers,
|
||||
function_handlers = function_handlers,
|
||||
function_nth_tick_handlers = function_nth_tick_handlers
|
||||
},
|
||||
function(tbl)
|
||||
token_handlers = tbl.token_handlers
|
||||
token_nth_tick_handlers = tbl.token_nth_tick_handlers
|
||||
function_handlers = tbl.function_handlers
|
||||
function_nth_tick_handlers = tbl.function_nth_tick_handlers
|
||||
end
|
||||
)
|
||||
|
||||
local function remove(tbl, handler)
|
||||
if tbl == nil then
|
||||
return
|
||||
end
|
||||
|
||||
-- the handler we are looking for is more likely to be at the back of the array.
|
||||
for i = #tbl, 1, -1 do
|
||||
if tbl[i] == handler then
|
||||
table_remove(tbl, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Register a handler for the event_name event.
|
||||
-- This function must be called in the control stage or in Event.on_init or Event.on_load.
|
||||
-- See documentation at top of file for details on using events.
|
||||
-- @param event_name<number>
|
||||
-- @param handler<function>
|
||||
function Event.add(event_name, handler)
|
||||
if _LIFECYCLE == 8 then
|
||||
error('Calling Event.add after on_init() or on_load() has run is a desync risk.', 2)
|
||||
end
|
||||
|
||||
core_add(event_name, handler)
|
||||
end
|
||||
|
||||
--- Register a handler for the script.on_init event.
|
||||
-- This function must be called in the control stage or in Event.on_init or Event.on_load
|
||||
-- See documentation at top of file for details on using events.
|
||||
-- @param handler<function>
|
||||
function Event.on_init(handler)
|
||||
if _LIFECYCLE == 8 then
|
||||
error('Calling Event.on_init after on_init() or on_load() has run is a desync risk.', 2)
|
||||
end
|
||||
|
||||
core_on_init(handler)
|
||||
end
|
||||
|
||||
--- Register a handler for the script.on_load event.
|
||||
-- This function must be called in the control stage or in Event.on_init or Event.on_load
|
||||
-- See documentation at top of file for details on using events.
|
||||
-- @param handler<function>
|
||||
function Event.on_load(handler)
|
||||
if _LIFECYCLE == 8 then
|
||||
error('Calling Event.on_load after on_init() or on_load() has run is a desync risk.', 2)
|
||||
end
|
||||
|
||||
core_on_load(handler)
|
||||
end
|
||||
|
||||
--- Register a handler for the nth_tick event.
|
||||
-- This function must be called in the control stage or in Event.on_init or Event.on_load.
|
||||
-- See documentation at top of file for details on using events.
|
||||
-- @param tick<number> The handler will be called every nth tick
|
||||
-- @param handler<function>
|
||||
function Event.on_nth_tick(tick, handler)
|
||||
if _LIFECYCLE == 8 then
|
||||
error('Calling Event.on_nth_tick after on_init() or on_load() has run is a desync risk.', 2)
|
||||
end
|
||||
|
||||
core_on_nth_tick(tick, handler)
|
||||
end
|
||||
|
||||
--- Register a token handler that can be safely added and removed at runtime.
|
||||
-- Do NOT call this method during on_load.
|
||||
-- See documentation at top of file for details on using events.
|
||||
-- @param event_name<number>
|
||||
-- @param token<number>
|
||||
function Event.add_removable(event_name, token)
|
||||
if type(token) ~= 'number' then
|
||||
error('token must be a number', 2)
|
||||
end
|
||||
if _LIFECYCLE == stage_load then
|
||||
error('cannot call during on_load', 2)
|
||||
end
|
||||
|
||||
local tokens = token_handlers[event_name]
|
||||
if not tokens then
|
||||
token_handlers[event_name] = {token}
|
||||
else
|
||||
tokens[#tokens + 1] = token
|
||||
end
|
||||
|
||||
if handlers_added then
|
||||
local handler = Token.get(token)
|
||||
core_add(event_name, handler)
|
||||
end
|
||||
end
|
||||
|
||||
--- Removes a token handler for the given event_name.
|
||||
-- Do NOT call this method during on_load.
|
||||
-- See documentation at top of file for details on using events.
|
||||
-- @param event_name<number>
|
||||
-- @param token<number>
|
||||
function Event.remove_removable(event_name, token)
|
||||
if _LIFECYCLE == stage_load then
|
||||
error('cannot call during on_load', 2)
|
||||
end
|
||||
local tokens = token_handlers[event_name]
|
||||
|
||||
if not tokens then
|
||||
return
|
||||
end
|
||||
|
||||
local handler = Token.get(token)
|
||||
local handlers = event_handlers[event_name]
|
||||
|
||||
remove(tokens, token)
|
||||
remove(handlers, handler)
|
||||
|
||||
if #handlers == 0 then
|
||||
script_on_event(event_name, nil)
|
||||
end
|
||||
end
|
||||
|
||||
--- Register a handler that can be safely added and removed at runtime.
|
||||
-- The handler must not be a closure, as that is a desync risk.
|
||||
-- Do NOT call this method during on_load.
|
||||
-- See documentation at top of file for details on using events.
|
||||
-- @param event_name<number>
|
||||
-- @param func<function>
|
||||
function Event.add_removable_function(event_name, func)
|
||||
if _LIFECYCLE == stage_load then
|
||||
error('cannot call during on_load', 2)
|
||||
end
|
||||
if type(func) ~= 'function' then
|
||||
error('func must be a function', 2)
|
||||
end
|
||||
|
||||
if Debug.is_closure(func) then
|
||||
error(
|
||||
'func cannot be a closure as that is a desync risk. Consider using Event.add_removable(event_name, token) instead.',
|
||||
2
|
||||
)
|
||||
end
|
||||
|
||||
local functions = function_handlers[event_name]
|
||||
if not functions then
|
||||
function_handlers[event_name] = {func}
|
||||
else
|
||||
functions[#functions + 1] = func
|
||||
end
|
||||
|
||||
if handlers_added then
|
||||
core_add(event_name, func)
|
||||
end
|
||||
end
|
||||
|
||||
--- Removes a handler for the given event_name.
|
||||
-- Do NOT call this method during on_load.
|
||||
-- See documentation at top of file for details on using events.
|
||||
-- @param event_name<number>
|
||||
-- @param func<function>
|
||||
function Event.remove_removable_function(event_name, func)
|
||||
if _LIFECYCLE == stage_load then
|
||||
error('cannot call during on_load', 2)
|
||||
end
|
||||
local functions = function_handlers[event_name]
|
||||
|
||||
if not functions then
|
||||
return
|
||||
end
|
||||
|
||||
local handlers = event_handlers[event_name]
|
||||
|
||||
remove(functions, func)
|
||||
remove(handlers, func)
|
||||
|
||||
if #handlers == 0 then
|
||||
script_on_event(event_name, nil)
|
||||
end
|
||||
end
|
||||
|
||||
--- Register a token handler for the nth tick that can be safely added and removed at runtime.
|
||||
-- Do NOT call this method during on_load.
|
||||
-- See documentation at top of file for details on using events.
|
||||
-- @param tick<number>
|
||||
-- @param token<number>
|
||||
function Event.add_removable_nth_tick(tick, token)
|
||||
if _LIFECYCLE == stage_load then
|
||||
error('cannot call during on_load', 2)
|
||||
end
|
||||
if type(token) ~= 'number' then
|
||||
error('token must be a number', 2)
|
||||
end
|
||||
|
||||
local tokens = token_nth_tick_handlers[tick]
|
||||
if not tokens then
|
||||
token_nth_tick_handlers[tick] = {token}
|
||||
else
|
||||
tokens[#tokens + 1] = token
|
||||
end
|
||||
|
||||
if handlers_added then
|
||||
local handler = Token.get(token)
|
||||
core_on_nth_tick(tick, handler)
|
||||
end
|
||||
end
|
||||
|
||||
--- Removes a token handler for the nth tick.
|
||||
-- Do NOT call this method during on_load.
|
||||
-- See documentation at top of file for details on using events.
|
||||
-- @param tick<number>
|
||||
-- @param token<number>
|
||||
function Event.remove_removable_nth_tick(tick, token)
|
||||
if _LIFECYCLE == stage_load then
|
||||
error('cannot call during on_load', 2)
|
||||
end
|
||||
local tokens = token_nth_tick_handlers[tick]
|
||||
|
||||
if not tokens then
|
||||
return
|
||||
end
|
||||
|
||||
local handler = Token.get(token)
|
||||
local handlers = on_nth_tick_event_handlers[tick]
|
||||
|
||||
remove(tokens, token)
|
||||
remove(handlers, handler)
|
||||
|
||||
if #handlers == 0 then
|
||||
script_on_nth_tick(tick, nil)
|
||||
end
|
||||
end
|
||||
|
||||
--- Register a handler for the nth tick that can be safely added and removed at runtime.
|
||||
-- The handler must not be a closure, as that is a desync risk.
|
||||
-- Do NOT call this method during on_load.
|
||||
-- See documentation at top of file for details on using events.
|
||||
-- @param tick<number>
|
||||
-- @param func<function>
|
||||
function Event.add_removable_nth_tick_function(tick, func)
|
||||
if _LIFECYCLE == stage_load then
|
||||
error('cannot call during on_load', 2)
|
||||
end
|
||||
if type(func) ~= 'function' then
|
||||
error('func must be a function', 2)
|
||||
end
|
||||
|
||||
if Debug.is_closure(func) then
|
||||
error(
|
||||
'func cannot be a closure as that is a desync risk. Consider using Event.add_removable_nth_tick(tick, token) instead.',
|
||||
2
|
||||
)
|
||||
end
|
||||
|
||||
local functions = function_nth_tick_handlers[tick]
|
||||
if not functions then
|
||||
function_nth_tick_handlers[tick] = {func}
|
||||
else
|
||||
functions[#functions + 1] = func
|
||||
end
|
||||
|
||||
if handlers_added then
|
||||
core_on_nth_tick(tick, func)
|
||||
end
|
||||
end
|
||||
|
||||
--- Removes a handler for the nth tick.
|
||||
-- Do NOT call this method during on_load.
|
||||
-- See documentation at top of file for details on using events.
|
||||
-- @param tick<number>
|
||||
-- @param func<function>
|
||||
function Event.remove_removable_nth_tick_function(tick, func)
|
||||
if _LIFECYCLE == stage_load then
|
||||
error('cannot call during on_load', 2)
|
||||
end
|
||||
local functions = function_nth_tick_handlers[tick]
|
||||
|
||||
if not functions then
|
||||
return
|
||||
end
|
||||
|
||||
local handlers = on_nth_tick_event_handlers[tick]
|
||||
|
||||
remove(functions, func)
|
||||
remove(handlers, func)
|
||||
|
||||
if #handlers == 0 then
|
||||
script_on_nth_tick(tick, nil)
|
||||
end
|
||||
end
|
||||
|
||||
local function add_handlers()
|
||||
for event_name, tokens in pairs(token_handlers) do
|
||||
for i = 1, #tokens do
|
||||
local handler = Token.get(tokens[i])
|
||||
core_add(event_name, handler)
|
||||
end
|
||||
end
|
||||
|
||||
for event_name, functions in pairs(function_handlers) do
|
||||
for i = 1, #functions do
|
||||
local handler = functions[i]
|
||||
core_add(event_name, handler)
|
||||
end
|
||||
end
|
||||
|
||||
for tick, tokens in pairs(token_nth_tick_handlers) do
|
||||
for i = 1, #tokens do
|
||||
local handler = Token.get(tokens[i])
|
||||
core_on_nth_tick(tick, handler)
|
||||
end
|
||||
end
|
||||
|
||||
for tick, functions in pairs(function_nth_tick_handlers) do
|
||||
for i = 1, #functions do
|
||||
local handler = functions[i]
|
||||
core_on_nth_tick(tick, handler)
|
||||
end
|
||||
end
|
||||
|
||||
handlers_added = true
|
||||
end
|
||||
|
||||
core_on_init(add_handlers)
|
||||
core_on_load(add_handlers)
|
||||
|
||||
return Event
|
||||
137
exp_legacy/module/utils/event_core.lua
Normal file
137
exp_legacy/module/utils/event_core.lua
Normal file
@@ -0,0 +1,137 @@
|
||||
-- This module exists to break the circular dependency between event.lua and global.lua.
|
||||
-- It is not expected that any user code would require this module instead event.lua should be required.
|
||||
|
||||
local Public = {}
|
||||
|
||||
local init_event_name = -1
|
||||
local load_event_name = -2
|
||||
|
||||
-- map of event_name to handlers[]
|
||||
local event_handlers = {}
|
||||
-- map of nth_tick to handlers[]
|
||||
local on_nth_tick_event_handlers = {}
|
||||
|
||||
local trace = debug.traceback
|
||||
local xpcall = xpcall
|
||||
local log = log
|
||||
local script_on_event = script.on_event
|
||||
local script_on_nth_tick = script.on_nth_tick
|
||||
|
||||
local function handler_error(err)
|
||||
log('\n\t'..trace(err))
|
||||
end
|
||||
|
||||
local function call_handlers(handlers, event)
|
||||
if _DEBUG then
|
||||
for i = 1, #handlers do
|
||||
local handler = handlers[i]
|
||||
handler(event)
|
||||
end
|
||||
else
|
||||
for i = 1, #handlers do
|
||||
xpcall(handlers[i], handler_error, event)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function on_event(event)
|
||||
local handlers = event_handlers[event.name]
|
||||
call_handlers(handlers, event)
|
||||
end
|
||||
|
||||
local function on_init()
|
||||
_LIFECYCLE = 5 -- on_init
|
||||
log('[INFO] Entering on_init')
|
||||
local handlers = event_handlers[init_event_name]
|
||||
call_handlers(handlers)
|
||||
|
||||
event_handlers[init_event_name] = nil
|
||||
event_handlers[load_event_name] = nil
|
||||
|
||||
_LIFECYCLE = 8 -- Runtime
|
||||
log('[INFO] Entering runtime')
|
||||
end
|
||||
|
||||
local function on_load()
|
||||
_LIFECYCLE = 6 -- on_load
|
||||
log('[INFO] Entering on_load')
|
||||
local handlers = event_handlers[load_event_name]
|
||||
call_handlers(handlers)
|
||||
|
||||
event_handlers[init_event_name] = nil
|
||||
event_handlers[load_event_name] = nil
|
||||
|
||||
_LIFECYCLE = 8 -- Runtime
|
||||
log('[INFO] Entering runtime')
|
||||
end
|
||||
|
||||
local function on_nth_tick_event(event)
|
||||
local handlers = on_nth_tick_event_handlers[event.nth_tick]
|
||||
call_handlers(handlers, event)
|
||||
end
|
||||
|
||||
--- Do not use this function, use Event.add instead as it has safety checks.
|
||||
function Public.add(event_name, handler)
|
||||
local handlers = event_handlers[event_name]
|
||||
if not handlers then
|
||||
event_handlers[event_name] = {handler}
|
||||
script_on_event(event_name, on_event)
|
||||
else
|
||||
table.insert(handlers, handler)
|
||||
if #handlers == 1 then
|
||||
script_on_event(event_name, on_event)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Do not use this function, use Event.on_init instead as it has safety checks.
|
||||
function Public.on_init(handler)
|
||||
local handlers = event_handlers[init_event_name]
|
||||
if not handlers then
|
||||
event_handlers[init_event_name] = {handler}
|
||||
script.on_init(on_init)
|
||||
else
|
||||
table.insert(handlers, handler)
|
||||
if #handlers == 1 then
|
||||
script.on_init(on_init)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Do not use this function, use Event.on_load instead as it has safety checks.
|
||||
function Public.on_load(handler)
|
||||
local handlers = event_handlers[load_event_name]
|
||||
if not handlers then
|
||||
event_handlers[load_event_name] = {handler}
|
||||
script.on_load(on_load)
|
||||
else
|
||||
table.insert(handlers, handler)
|
||||
if #handlers == 1 then
|
||||
script.on_load(on_load)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Do not use this function, use Event.on_nth_tick instead as it has safety checks.
|
||||
function Public.on_nth_tick(tick, handler)
|
||||
local handlers = on_nth_tick_event_handlers[tick]
|
||||
if not handlers then
|
||||
on_nth_tick_event_handlers[tick] = {handler}
|
||||
script_on_nth_tick(tick, on_nth_tick_event)
|
||||
else
|
||||
table.insert(handlers, handler)
|
||||
if #handlers == 1 then
|
||||
script_on_nth_tick(tick, on_nth_tick_event)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Public.get_event_handlers()
|
||||
return event_handlers
|
||||
end
|
||||
|
||||
function Public.get_on_nth_tick_event_handlers()
|
||||
return on_nth_tick_event_handlers
|
||||
end
|
||||
|
||||
return Public
|
||||
109
exp_legacy/module/utils/game.lua
Normal file
109
exp_legacy/module/utils/game.lua
Normal file
@@ -0,0 +1,109 @@
|
||||
|
||||
local Color = require 'utils.color_presets' --- @dep utils.color_presets
|
||||
local Game = {}
|
||||
|
||||
--[[ Note to readers
|
||||
Game.get_player_from_name was removed because game.players[name] works without any edge cases
|
||||
always true: game.players[name].name == name
|
||||
|
||||
Game.get_player_by_index was added originally as a workaround for the following edge case:
|
||||
player with index of 5 and name of "Cooldude2606"
|
||||
player with index of 10 and name of "5"
|
||||
game.players[5].name == "5"
|
||||
|
||||
Discovered the following logic:
|
||||
all keys are first converted to string and search against player names
|
||||
if this fails it attempts to convert it to a number and search against player indexes
|
||||
sometimes fails: game.players[index].index == index
|
||||
|
||||
Game.get_player_by_index was removed after the above logic was corrected to the following:
|
||||
when a key is a number it is searched against player indexes, and only their indexes
|
||||
when a key is a string it is searched against player names, and then against their indexes
|
||||
always true: game.players[name].name == name; game.players[index].index == index
|
||||
|
||||
]]
|
||||
|
||||
--- Returns a valid LuaPlayer if given a number, string, or LuaPlayer. Returns nil otherwise.
|
||||
-- obj <number|string|LuaPlayer>
|
||||
function Game.get_player_from_any(obj)
|
||||
local o_type, p = type(obj)
|
||||
if o_type == 'table' then
|
||||
p = obj
|
||||
elseif o_type == 'string' or o_type == 'number' then
|
||||
p = game.players[obj]
|
||||
end
|
||||
|
||||
if p and p.valid and p.is_player() then
|
||||
return p
|
||||
end
|
||||
end
|
||||
|
||||
--- Prints to player or console.
|
||||
-- @param str <string|table> table if locale is used
|
||||
-- @param color <table> defaults to white
|
||||
function Game.player_print(str, color)
|
||||
color = color or Color.white
|
||||
if game.player then
|
||||
game.player.print(str, color)
|
||||
else
|
||||
print(str)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Creates a floating text entity at a location with the specified color.
|
||||
Example: "+10 iron" or "-10 coins"
|
||||
|
||||
@param surface LuaSurface
|
||||
@param position String to display at
|
||||
@param text String to display
|
||||
@param color table in {r = 0~1, g = 0~1, b = 0~1}, defaults to white.
|
||||
|
||||
@return the created entity
|
||||
]]
|
||||
function Game.print_floating_text(surface, position, text, color)
|
||||
color = color or Color.white
|
||||
|
||||
return surface.create_entity {
|
||||
name = 'tutorial-flying-text',
|
||||
color = color,
|
||||
text = text,
|
||||
position = position
|
||||
}
|
||||
end
|
||||
|
||||
--[[
|
||||
Creates a floating text entity at the player location with the specified color and offset.
|
||||
Example: "+10 iron" or "-10 coins"
|
||||
|
||||
@param text String to display
|
||||
@param color table in {r = 0~1, g = 0~1, b = 0~1}, defaults to white.
|
||||
@param x_offset number the x offset for the floating text
|
||||
@param y_offset number the y offset for the floating text
|
||||
|
||||
@return the created entity
|
||||
]]
|
||||
function Game.print_player_floating_text_position(player, text, color, x_offset, y_offset)
|
||||
player = Game.get_player_from_any(player)
|
||||
if not player or not player.valid then
|
||||
return
|
||||
end
|
||||
|
||||
local position = player.position
|
||||
return Game.print_floating_text(player.surface, {x = position.x + x_offset, y = position.y + y_offset}, text, color)
|
||||
end
|
||||
|
||||
--[[
|
||||
Creates a floating text entity at the player location with the specified color in {r, g, b} format.
|
||||
Example: "+10 iron" or "-10 coins"
|
||||
|
||||
@param text String to display
|
||||
@param color table in {r = 0~1, g = 0~1, b = 0~1}, defaults to white.
|
||||
|
||||
@return the created entity
|
||||
]]
|
||||
function Game.print_player_floating_text(player, text, color)
|
||||
Game.print_player_floating_text_position(player, text, color, 0, -1.5)
|
||||
end
|
||||
|
||||
return Game
|
||||
79
exp_legacy/module/utils/global.lua
Normal file
79
exp_legacy/module/utils/global.lua
Normal file
@@ -0,0 +1,79 @@
|
||||
local Event = require 'utils.event_core' --- @dep utils.event_core
|
||||
local Token = require 'utils.token' --- @dep utils.token
|
||||
|
||||
local Global = {}
|
||||
|
||||
function Global.register(tbl, callback)
|
||||
if _LIFECYCLE ~= _STAGE.control then
|
||||
error('can only be called during the control stage', 2)
|
||||
end
|
||||
local token = Token.register_global(tbl)
|
||||
|
||||
Event.on_load(
|
||||
function()
|
||||
callback(Token.get_global(token))
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
function Global.register_init(tbl, init_handler, callback)
|
||||
if _LIFECYCLE ~= _STAGE.control then
|
||||
error('can only be called during the control stage', 2)
|
||||
end
|
||||
local token = Token.register_global(tbl)
|
||||
|
||||
Event.on_init(
|
||||
function()
|
||||
init_handler(tbl)
|
||||
callback(tbl)
|
||||
end
|
||||
)
|
||||
|
||||
Event.on_load(
|
||||
function()
|
||||
callback(Token.get_global(token))
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
if _DEBUG or true then
|
||||
local concat = table.concat
|
||||
|
||||
local names = {}
|
||||
Global.names = names
|
||||
|
||||
function Global.register(tbl, callback)
|
||||
local filepath = debug.getinfo(2, 'S').source:match('^.+/currently%-playing/(.+)$'):sub(1, -5)
|
||||
local token = Token.register_global(tbl)
|
||||
|
||||
names[token] = concat {token, ' - ', filepath}
|
||||
|
||||
Event.on_load(
|
||||
function()
|
||||
callback(Token.get_global(token))
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
function Global.register_init(tbl, init_handler, callback)
|
||||
local filepath = debug.getinfo(2, 'S').source:match('^.+/currently%-playing/(.+)$'):sub(1, -5)
|
||||
local token = Token.register_global(tbl)
|
||||
|
||||
names[token] = concat {token, ' - ', filepath}
|
||||
|
||||
Event.on_init(
|
||||
function()
|
||||
init_handler(tbl)
|
||||
callback(tbl)
|
||||
end
|
||||
)
|
||||
|
||||
Event.on_load(
|
||||
function()
|
||||
callback(Token.get_global(token))
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
return Global
|
||||
132
exp_legacy/module/utils/gui.lua
Normal file
132
exp_legacy/module/utils/gui.lua
Normal file
@@ -0,0 +1,132 @@
|
||||
local Global = require 'utils.global' --- @dep utils.global
|
||||
local Event = require 'utils.event' --- @dep expcore.gui
|
||||
local mod_gui = require 'mod-gui' --- @dep mod-gui
|
||||
|
||||
local Gui = {}
|
||||
local data = {}
|
||||
local uid = 0
|
||||
|
||||
Global.register(
|
||||
data,
|
||||
function(tbl)
|
||||
data = tbl
|
||||
end
|
||||
)
|
||||
|
||||
function Gui.uid_name()
|
||||
uid = uid + 1
|
||||
return "Redmew_"..uid
|
||||
end
|
||||
|
||||
-- Associates data with the LuaGuiElement. If data is nil then removes the data
|
||||
function Gui.set_data(element, value)
|
||||
data[element.player_index * 0x100000000 + element.index] = value
|
||||
end
|
||||
|
||||
-- Gets the Associated data with this LuaGuiElement if any.
|
||||
function Gui.get_data(element)
|
||||
return data[element.player_index * 0x100000000 + element.index]
|
||||
end
|
||||
|
||||
-- Removes data associated with LuaGuiElement and its children recursively.
|
||||
function Gui.remove_data_recursively(element)
|
||||
Gui.set_data(element, nil)
|
||||
|
||||
local children = element.children
|
||||
|
||||
if not children then
|
||||
return
|
||||
end
|
||||
|
||||
for _, child in ipairs(children) do
|
||||
if child.valid then
|
||||
Gui.remove_data_recursively(child)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Gui.remove_children_data(element)
|
||||
local children = element.children
|
||||
|
||||
if not children then
|
||||
return
|
||||
end
|
||||
|
||||
for _, child in ipairs(children) do
|
||||
if child.valid then
|
||||
Gui.set_data(child, nil)
|
||||
Gui.remove_children_data(child)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Gui.destroy(element)
|
||||
Gui.remove_data_recursively(element)
|
||||
element.destroy()
|
||||
end
|
||||
|
||||
function Gui.clear(element)
|
||||
Gui.remove_children_data(element)
|
||||
element.clear()
|
||||
end
|
||||
|
||||
local function handler_factory(event_name)
|
||||
return function(element_name, handler)
|
||||
Event.add(defines.events[event_name], function(event)
|
||||
if event.element and event.element.valid and event.element.name == element_name then
|
||||
event.player = game.get_player(event.player_index)
|
||||
handler(event)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- Register a handler for the on_gui_checked_state_changed event for LuaGuiElements with element_name.
|
||||
-- Can only have one handler per element name.
|
||||
-- Guarantees that the element and the player are valid when calling the handler.
|
||||
-- Adds a player field to the event table.
|
||||
Gui.on_checked_state_changed = handler_factory('on_gui_checked_state_changed')
|
||||
|
||||
-- Register a handler for the on_gui_click event for LuaGuiElements with element_name.
|
||||
-- Can only have one handler per element name.
|
||||
-- Guarantees that the element and the player are valid when calling the handler.
|
||||
-- Adds a player field to the event table.
|
||||
Gui.on_click = handler_factory('on_gui_click')
|
||||
|
||||
-- Register a handler for the on_gui_closed event for a custom LuaGuiElements with element_name.
|
||||
-- Can only have one handler per element name.
|
||||
-- Guarantees that the element and the player are valid when calling the handler.
|
||||
-- Adds a player field to the event table.
|
||||
Gui.on_custom_close = handler_factory('on_gui_closed')
|
||||
|
||||
-- Register a handler for the on_gui_elem_changed event for LuaGuiElements with element_name.
|
||||
-- Can only have one handler per element name.
|
||||
-- Guarantees that the element and the player are valid when calling the handler.
|
||||
-- Adds a player field to the event table.
|
||||
Gui.on_elem_changed = handler_factory('on_gui_elem_changed')
|
||||
|
||||
-- Register a handler for the on_gui_selection_state_changed event for LuaGuiElements with element_name.
|
||||
-- Can only have one handler per element name.
|
||||
-- Guarantees that the element and the player are valid when calling the handler.
|
||||
-- Adds a player field to the event table.
|
||||
Gui.on_selection_state_changed = handler_factory('on_gui_selection_state_changed')
|
||||
|
||||
-- Register a handler for the on_gui_text_changed event for LuaGuiElements with element_name.
|
||||
-- Can only have one handler per element name.
|
||||
-- Guarantees that the element and the player are valid when calling the handler.
|
||||
-- Adds a player field to the event table.
|
||||
Gui.on_text_changed = handler_factory('on_gui_text_changed')
|
||||
|
||||
-- Register a handler for the on_gui_value_changed event for LuaGuiElements with element_name.
|
||||
-- Can only have one handler per element name.
|
||||
-- Guarantees that the element and the player are valid when calling the handler.
|
||||
-- Adds a player field to the event table.
|
||||
Gui.on_value_changed = handler_factory('on_gui_value_changed')
|
||||
|
||||
--- Returns the flow where top elements can be added and will be effected by google visibility
|
||||
-- For the toggle to work it must be registed with Gui.allow_player_to_toggle_top_element_visibility(element_name)
|
||||
-- @tparam LuaPlayer player pointer to the player who has the gui
|
||||
-- @treturn LuaGuiElement the top element flow
|
||||
Gui.get_top_element_flow = mod_gui.get_button_flow
|
||||
|
||||
return Gui
|
||||
74
exp_legacy/module/utils/priority_queue.lua
Normal file
74
exp_legacy/module/utils/priority_queue.lua
Normal file
@@ -0,0 +1,74 @@
|
||||
local PriorityQueue = {}
|
||||
|
||||
function PriorityQueue.new()
|
||||
return {}
|
||||
end
|
||||
|
||||
local function default_comp(a, b)
|
||||
return a < b
|
||||
end
|
||||
|
||||
local function HeapifyFromEndToStart(queue, comp)
|
||||
comp = comp or default_comp
|
||||
local pos = #queue
|
||||
while pos > 1 do
|
||||
local parent = bit32.rshift(pos, 1) -- integer division by 2
|
||||
if comp(queue[pos], queue[parent]) then
|
||||
queue[pos], queue[parent] = queue[parent], queue[pos]
|
||||
pos = parent
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function HeapifyFromStartToEnd(queue, comp)
|
||||
comp = comp or default_comp
|
||||
local parent = 1
|
||||
local smallest = 1
|
||||
while true do
|
||||
local child = parent * 2
|
||||
if child > #queue then
|
||||
break
|
||||
end
|
||||
if comp(queue[child], queue[parent]) then
|
||||
smallest = child
|
||||
end
|
||||
child = child + 1
|
||||
if child <= #queue and comp(queue[child], queue[smallest]) then
|
||||
smallest = child
|
||||
end
|
||||
|
||||
if parent ~= smallest then
|
||||
queue[parent], queue[smallest] = queue[smallest], queue[parent]
|
||||
parent = smallest
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PriorityQueue.size(queue)
|
||||
return #queue
|
||||
end
|
||||
|
||||
function PriorityQueue.push(queue, element, comp)
|
||||
table.insert(queue, element)
|
||||
HeapifyFromEndToStart(queue, comp)
|
||||
end
|
||||
|
||||
function PriorityQueue.pop(queue, comp)
|
||||
local element = queue[1]
|
||||
|
||||
queue[1] = queue[#queue]
|
||||
queue[#queue] = nil
|
||||
HeapifyFromStartToEnd(queue, comp)
|
||||
|
||||
return element
|
||||
end
|
||||
|
||||
function PriorityQueue.peek(queue)
|
||||
return queue[1]
|
||||
end
|
||||
|
||||
return PriorityQueue
|
||||
34
exp_legacy/module/utils/queue.lua
Normal file
34
exp_legacy/module/utils/queue.lua
Normal file
@@ -0,0 +1,34 @@
|
||||
local Queue = {}
|
||||
|
||||
function Queue.new()
|
||||
local queue = {_head = 0, _tail = 0}
|
||||
return queue
|
||||
end
|
||||
|
||||
function Queue.size(queue)
|
||||
return queue._tail - queue._head
|
||||
end
|
||||
|
||||
function Queue.push(queue, element)
|
||||
local index = queue._head
|
||||
queue[index] = element
|
||||
queue._head = index - 1
|
||||
end
|
||||
|
||||
function Queue.peek(queue)
|
||||
return queue[queue._tail]
|
||||
end
|
||||
|
||||
function Queue.pop(queue)
|
||||
local index = queue._tail
|
||||
|
||||
local element = queue[index]
|
||||
queue[index] = nil
|
||||
|
||||
if element then
|
||||
queue._tail = index - 1
|
||||
end
|
||||
return element
|
||||
end
|
||||
|
||||
return Queue
|
||||
115
exp_legacy/module/utils/task.lua
Normal file
115
exp_legacy/module/utils/task.lua
Normal file
@@ -0,0 +1,115 @@
|
||||
--- Threading simulation module
|
||||
-- Task.sleep()
|
||||
-- @author Valansch and Grilledham
|
||||
-- github: https://github.com/Refactorio/RedMew
|
||||
-- ======================================================= --
|
||||
|
||||
local Queue = require 'utils.queue' --- @dep utils.queue
|
||||
local PriorityQueue = require 'utils.priority_queue' --- @dep utils.priority_queue
|
||||
local Event = require 'utils.event' --- @dep utils.event
|
||||
local Token = require 'utils.token' --- @dep utils.token
|
||||
|
||||
local Task = {}
|
||||
|
||||
global.callbacks = global.callbacks or PriorityQueue.new()
|
||||
global.next_async_callback_time = -1
|
||||
global.task_queue = global.task_queue or Queue.new()
|
||||
global.total_task_weight = 0
|
||||
global.task_queue_speed = 1
|
||||
|
||||
local function comp(a, b)
|
||||
return a.time < b.time
|
||||
end
|
||||
|
||||
global.tpt = global.task_queue_speed
|
||||
local function get_task_per_tick()
|
||||
if game.tick % 300 == 0 then
|
||||
local size = global.total_task_weight
|
||||
global.tpt = math.floor(math.log(size + 1, 10)) * global.task_queue_speed
|
||||
if global.tpt < 1 then
|
||||
global.tpt = 1
|
||||
end
|
||||
end
|
||||
return global.tpt
|
||||
end
|
||||
|
||||
local function on_tick()
|
||||
local queue = global.task_queue
|
||||
for i = 1, get_task_per_tick() do
|
||||
local task = Queue.peek(queue)
|
||||
if task ~= nil then
|
||||
-- result is error if not success else result is a boolean for if the task should stay in the queue.
|
||||
local success, result = pcall(Token.get(task.func_token), task.params)
|
||||
if not success then
|
||||
if _DEBUG then
|
||||
error(result)
|
||||
else
|
||||
log(result)
|
||||
end
|
||||
Queue.pop(queue)
|
||||
global.total_task_weight = global.total_task_weight - task.weight
|
||||
elseif not result then
|
||||
Queue.pop(queue)
|
||||
global.total_task_weight = global.total_task_weight - task.weight
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local callbacks = global.callbacks
|
||||
local callback = PriorityQueue.peek(callbacks)
|
||||
while callback ~= nil and game.tick >= callback.time do
|
||||
local success, result = pcall(Token.get(callback.func_token), callback.params)
|
||||
if not success then
|
||||
if _DEBUG then
|
||||
error(result)
|
||||
else
|
||||
log(result)
|
||||
end
|
||||
end
|
||||
PriorityQueue.pop(callbacks, comp)
|
||||
callback = PriorityQueue.peek(callbacks)
|
||||
end
|
||||
end
|
||||
|
||||
--- Allows you to set a timer (in ticks) after which the tokened function will be run with params given as an argument
|
||||
-- Cannot be called before init
|
||||
-- @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
|
||||
function Task.set_timeout_in_ticks(ticks, func_token, params)
|
||||
if not game then
|
||||
error('cannot call when game is not available', 2)
|
||||
end
|
||||
local time = game.tick + ticks
|
||||
local callback = {time = time, func_token = func_token, params = params}
|
||||
PriorityQueue.push(global.callbacks, callback, comp)
|
||||
end
|
||||
|
||||
--- Allows you to set a timer (in seconds) after which the tokened function will be run with params given as an argument
|
||||
-- Cannot be called before init
|
||||
-- @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
|
||||
function Task.set_timeout(sec, func_token, params)
|
||||
if not game then
|
||||
error('cannot call when game is not available', 2)
|
||||
end
|
||||
Task.set_timeout_in_ticks(60 * sec, func_token, params)
|
||||
end
|
||||
|
||||
--- 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)
|
||||
function Task.queue_task(func_token, params, weight)
|
||||
weight = weight or 1
|
||||
global.total_task_weight = global.total_task_weight + weight
|
||||
Queue.push(global.task_queue, {func_token = func_token, params = params, weight = weight})
|
||||
end
|
||||
|
||||
Event.add(defines.events.on_tick, on_tick)
|
||||
|
||||
return Task
|
||||
69
exp_legacy/module/utils/token.lua
Normal file
69
exp_legacy/module/utils/token.lua
Normal file
@@ -0,0 +1,69 @@
|
||||
local Token = {}
|
||||
|
||||
local tokens = {}
|
||||
|
||||
local counter = 0
|
||||
|
||||
--- Assigns a unique id for the given var.
|
||||
-- This function cannot be called after on_init() or on_load() has run as that is a desync risk.
|
||||
-- Typically this is used to register functions, so the id can be stored in the global table
|
||||
-- instead of the function. This is because closures cannot be safely stored in the global table.
|
||||
-- @param var<any>
|
||||
-- @return number the unique token for the variable.
|
||||
function Token.register(var)
|
||||
if _LIFECYCLE == 8 then
|
||||
error('Calling Token.register after on_init() or on_load() has run is a desync risk.', 2)
|
||||
end
|
||||
|
||||
counter = counter + 1
|
||||
|
||||
tokens[counter] = var
|
||||
|
||||
return counter
|
||||
end
|
||||
|
||||
function Token.get(token_id)
|
||||
return tokens[token_id]
|
||||
end
|
||||
|
||||
global.tokens = {}
|
||||
|
||||
function Token.register_global(var)
|
||||
local c = #global.tokens + 1
|
||||
|
||||
global.tokens[c] = var
|
||||
|
||||
return c
|
||||
end
|
||||
|
||||
function Token.get_global(token_id)
|
||||
return global.tokens[token_id]
|
||||
end
|
||||
|
||||
function Token.set_global(token_id, var)
|
||||
global.tokens[token_id] = var
|
||||
end
|
||||
|
||||
local uid_counter = 0
|
||||
|
||||
function Token.uid()
|
||||
if _LIFECYCLE == 8 then
|
||||
return Token.runtime_uid()
|
||||
end
|
||||
|
||||
uid_counter = uid_counter + 1
|
||||
|
||||
return uid_counter
|
||||
end
|
||||
|
||||
function Token.runtime_uid()
|
||||
if not global.uid_counter then
|
||||
global.uid_counter = 0
|
||||
end
|
||||
|
||||
global.uid_counter = global.uid_counter + 1
|
||||
|
||||
return global.uid_counter+uid_counter
|
||||
end
|
||||
|
||||
return Token
|
||||
Reference in New Issue
Block a user