Move files to exp_legacy

This commit is contained in:
Cooldude2606
2024-09-23 15:55:28 +01:00
parent 446e87b610
commit 65145b5d34
266 changed files with 73 additions and 0 deletions

View 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}
}

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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