mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 11:35:22 +09:00
File loader with redmew files
This commit is contained in:
12
control.lua
12
control.lua
@@ -1,4 +1,4 @@
|
|||||||
--[[ not_luadoc=true
|
-- not_luadoc=true
|
||||||
function _log(...) log(...) end -- do not remove this is used for smaller verbose lines
|
function _log(...) log(...) end -- do not remove this is used for smaller verbose lines
|
||||||
Manager = require("FactorioSoftmodManager")
|
Manager = require("FactorioSoftmodManager")
|
||||||
Manager.setVerbose{
|
Manager.setVerbose{
|
||||||
@@ -12,15 +12,16 @@ Manager.setVerbose{
|
|||||||
output=Manager._verbose -- can be: can be: print || log || other function
|
output=Manager._verbose -- can be: can be: print || log || other function
|
||||||
}
|
}
|
||||||
Manager() -- can be Manager.loadModules() if called else where
|
Manager() -- can be Manager.loadModules() if called else where
|
||||||
]]
|
|
||||||
|
|
||||||
|
|
||||||
|
--[[
|
||||||
|
require 'utils.data_stages'
|
||||||
local Container = require 'container'
|
local Container = require 'container'
|
||||||
Container.handlers = {
|
Container.handlers = {
|
||||||
--event
|
Event='utils.event',
|
||||||
--global
|
Global='utils.global',
|
||||||
error=error,
|
error=error,
|
||||||
logging=function(...) log(...) end,
|
logging=function(...) log(...) end,
|
||||||
--debug
|
|
||||||
tableToString=serpent.line
|
tableToString=serpent.line
|
||||||
}
|
}
|
||||||
Container.loadHandlers()
|
Container.loadHandlers()
|
||||||
@@ -28,3 +29,4 @@ Container.files = {
|
|||||||
'modules.test'
|
'modules.test'
|
||||||
}
|
}
|
||||||
Container.loadFiles()
|
Container.loadFiles()
|
||||||
|
]]
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
function thisIsATestFunction(...)
|
function thisIsATestFunction(...)
|
||||||
game.print(serpent.line({...}))
|
game.print(serpent.line({...}))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Event.add(defines.events.on_console_chat,function(event)
|
||||||
|
if event.player_index then game.print('Message: '..event.message) end
|
||||||
|
end)
|
||||||
13
utils/data_stages.lua
Normal file
13
utils/data_stages.lua
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
-- Info on the data lifecycle and how we use it: https://github.com/Refactorio/RedMew/wiki/The-data-lifecycle
|
||||||
|
-- Non-applicable stages are commented out.
|
||||||
|
_STAGE = {
|
||||||
|
--settings = 1,
|
||||||
|
--data = 2,
|
||||||
|
--migration = 3,
|
||||||
|
control = 4,
|
||||||
|
init = 5,
|
||||||
|
load = 6,
|
||||||
|
--config_change = 7,
|
||||||
|
runtime = 8
|
||||||
|
}
|
||||||
|
_LIFECYCLE = _STAGE.control
|
||||||
164
utils/debug.lua
Normal file
164
utils/debug.lua
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
-- localised functions
|
||||||
|
local format = string.format
|
||||||
|
local match = string.match
|
||||||
|
local gsub = string.gsub
|
||||||
|
local serialize = serpent.line
|
||||||
|
local debug_getupvalue = debug.getupvalue
|
||||||
|
|
||||||
|
-- this
|
||||||
|
local Debug = {}
|
||||||
|
|
||||||
|
global.debug_message_count = 0
|
||||||
|
|
||||||
|
---@return number next index
|
||||||
|
local function increment()
|
||||||
|
local next = global.debug_message_count + 1
|
||||||
|
global.debug_message_count = next
|
||||||
|
|
||||||
|
return next
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Takes the table output from debug.getinfo and pretties it
|
||||||
|
local function cleanup_debug(debug_table)
|
||||||
|
local short_src = match(debug_table.source, '/[^/]*/[^/]*$')
|
||||||
|
-- require will not return a valid string so short_src may be nil here
|
||||||
|
if short_src then
|
||||||
|
short_src = gsub(short_src, '%.lua', '')
|
||||||
|
end
|
||||||
|
|
||||||
|
return format('[function: %s file: %s line number: %s]', debug_table.name, short_src, debug_table.currentline)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Shows the given message if debug is enabled. Uses serpent to print non scalars.
|
||||||
|
-- @param message <table|string|number|boolean>
|
||||||
|
-- @param stack_traceback <number|nil> levels of stack trace to give, defaults to 1 level if nil
|
||||||
|
function Debug.print(message, trace_levels)
|
||||||
|
if not _DEBUG then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not trace_levels then
|
||||||
|
trace_levels = 2
|
||||||
|
else
|
||||||
|
trace_levels = trace_levels + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local traceback_string = ''
|
||||||
|
if type(message) ~= 'string' and type(message) ~= 'number' and type(message) ~= 'boolean' then
|
||||||
|
message = serialize(message)
|
||||||
|
end
|
||||||
|
|
||||||
|
message = format('[%d] %s', increment(), tostring(message))
|
||||||
|
|
||||||
|
if trace_levels >= 2 then
|
||||||
|
for i = 2, trace_levels do
|
||||||
|
local debug_table = debug.getinfo(i)
|
||||||
|
if debug_table then
|
||||||
|
traceback_string = format('%s -> %s', traceback_string, cleanup_debug(debug_table))
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
message = format('%s - Traceback%s', message, traceback_string)
|
||||||
|
end
|
||||||
|
|
||||||
|
if _LIFECYCLE == _STAGE.runtime then
|
||||||
|
game.print(message)
|
||||||
|
end
|
||||||
|
log(message)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function get(obj, prop)
|
||||||
|
return obj[prop]
|
||||||
|
end
|
||||||
|
|
||||||
|
local function get_lua_object_type_safe(obj)
|
||||||
|
local s, r = pcall(get, obj, 'help')
|
||||||
|
|
||||||
|
if not s then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
return r():match('Lua%a+')
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the value of the key inside the object
|
||||||
|
-- or 'InvalidLuaObject' if the LuaObject is invalid.
|
||||||
|
-- or 'InvalidLuaObjectKey' if the LuaObject does not have an entry at that key
|
||||||
|
-- @param object <table> LuaObject or metatable
|
||||||
|
-- @param key <string>
|
||||||
|
-- @return <any>
|
||||||
|
function Debug.get_meta_value(object, key)
|
||||||
|
if Debug.object_type(object) == 'InvalidLuaObject' then
|
||||||
|
return 'InvalidLuaObject'
|
||||||
|
end
|
||||||
|
|
||||||
|
local suc, value = pcall(get, object, key)
|
||||||
|
if not suc then
|
||||||
|
return 'InvalidLuaObjectKey'
|
||||||
|
end
|
||||||
|
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the Lua data type or the factorio LuaObject type
|
||||||
|
-- or 'NoHelpLuaObject' if the LuaObject does not have a help function
|
||||||
|
-- or 'InvalidLuaObject' if the LuaObject is invalid.
|
||||||
|
-- @param object <any>
|
||||||
|
-- @return string
|
||||||
|
function Debug.object_type(object)
|
||||||
|
local obj_type = type(object)
|
||||||
|
|
||||||
|
if obj_type ~= 'table' or type(object.__self) ~= 'userdata' then
|
||||||
|
return obj_type
|
||||||
|
end
|
||||||
|
|
||||||
|
local suc, valid = pcall(get, object, 'valid')
|
||||||
|
if not suc then
|
||||||
|
-- no 'valid' property
|
||||||
|
return get_lua_object_type_safe(object) or 'NoHelpLuaObject'
|
||||||
|
end
|
||||||
|
|
||||||
|
if not valid then
|
||||||
|
return 'InvalidLuaObject'
|
||||||
|
else
|
||||||
|
return get_lua_object_type_safe(object) or 'NoHelpLuaObject'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---Shows the given message if debug is on.
|
||||||
|
---@param position Position
|
||||||
|
---@param message string
|
||||||
|
function Debug.print_position(position, message)
|
||||||
|
Debug.print(format('%s %s', serialize(position), message))
|
||||||
|
end
|
||||||
|
|
||||||
|
---Executes the given callback if cheating is enabled.
|
||||||
|
---@param callback function
|
||||||
|
function Debug.cheat(callback)
|
||||||
|
if _CHEATS then
|
||||||
|
callback()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns true if the function is a closure, false otherwise.
|
||||||
|
-- A closure is a function that contains 'upvalues' or in other words
|
||||||
|
-- has a reference to a local variable defined outside the function's scope.
|
||||||
|
-- @param func<function>
|
||||||
|
-- @return boolean
|
||||||
|
function Debug.is_closure(func)
|
||||||
|
local i = 1
|
||||||
|
while true do
|
||||||
|
local n = debug_getupvalue(func, i)
|
||||||
|
|
||||||
|
if n == nil then
|
||||||
|
return false
|
||||||
|
elseif n ~= '_ENV' then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Debug
|
||||||
457
utils/event.lua
Normal file
457
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'
|
||||||
|
-- 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'
|
||||||
|
-- local Event = require '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'
|
||||||
|
--
|
||||||
|
-- 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'
|
||||||
|
--
|
||||||
|
-- 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'
|
||||||
|
local Global = require 'utils.global'
|
||||||
|
local Token = require 'utils.token'
|
||||||
|
local Debug = require 'utils.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 likly 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 funcs = function_handlers[event_name]
|
||||||
|
if not funcs then
|
||||||
|
function_handlers[event_name] = {func}
|
||||||
|
else
|
||||||
|
funcs[#funcs + 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 funcs = function_handlers[event_name]
|
||||||
|
|
||||||
|
if not funcs then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local handlers = event_handlers[event_name]
|
||||||
|
|
||||||
|
remove(funcs, 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 funcs = function_nth_tick_handlers[tick]
|
||||||
|
if not funcs then
|
||||||
|
function_nth_tick_handlers[tick] = {func}
|
||||||
|
else
|
||||||
|
funcs[#funcs + 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 funcs = function_nth_tick_handlers[tick]
|
||||||
|
|
||||||
|
if not funcs then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local handlers = on_nth_tick_event_handlers[tick]
|
||||||
|
|
||||||
|
remove(funcs, 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, funcs in pairs(function_handlers) do
|
||||||
|
for i = 1, #funcs do
|
||||||
|
local handler = funcs[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, funcs in pairs(function_nth_tick_handlers) do
|
||||||
|
for i = 1, #funcs do
|
||||||
|
local handler = funcs[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
|
||||||
132
utils/event_core.lua
Normal file
132
utils/event_core.lua
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
-- 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 pcall = pcall
|
||||||
|
local log = log
|
||||||
|
local script_on_event = script.on_event
|
||||||
|
local script_on_nth_tick = script.on_nth_tick
|
||||||
|
|
||||||
|
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
|
||||||
|
local handler = handlers[i]
|
||||||
|
local success, error = pcall(handler, event)
|
||||||
|
if not success then
|
||||||
|
log(error)
|
||||||
|
end
|
||||||
|
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
|
||||||
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
local function on_load()
|
||||||
|
_LIFECYCLE = 6 -- 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
|
||||||
|
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
|
||||||
79
utils/global.lua
Normal file
79
utils/global.lua
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
local Event = require 'utils.event_core'
|
||||||
|
local Token = require '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 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
|
||||||
55
utils/token.lua
Normal file
55
utils/token.lua
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
local Token = {}
|
||||||
|
|
||||||
|
local tokens = {}
|
||||||
|
|
||||||
|
local counter = 0
|
||||||
|
|
||||||
|
--- Assigns a unquie 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 becasue 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()
|
||||||
|
uid_counter = uid_counter + 1
|
||||||
|
|
||||||
|
return uid_counter
|
||||||
|
end
|
||||||
|
|
||||||
|
return Token
|
||||||
Reference in New Issue
Block a user