2018-12-28 18:21:45 +02:00
|
|
|
--- 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.
|
2019-01-06 22:58:43 +02:00
|
|
|
-- 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.
|
2018-12-28 18:21:45 +02:00
|
|
|
-- 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 occurance 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.
|
2019-01-07 22:05:23 +02:00
|
|
|
-- The same restrictions that apply to Event.add_removable also apply to Event.add_removable_function.
|
2018-12-28 18:21:45 +02:00
|
|
|
-- 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
|
|
|
|
|
2018-04-06 21:57:58 +02:00
|
|
|
local Event = {}
|
2017-06-13 13:16:07 +02:00
|
|
|
|
2019-01-03 19:23:41 +02:00
|
|
|
local handlers_added = false -- set to true after the removeable event handlers have been added.
|
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
local event_handlers = EventCore.get_event_handlers()
|
|
|
|
local on_nth_tick_event_handlers = EventCore.get_on_nth_tick_event_handlers()
|
2017-06-13 13:16:07 +02:00
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
local token_handlers = {}
|
|
|
|
local token_nth_tick_handlers = {}
|
|
|
|
local function_handlers = {}
|
|
|
|
local function_nth_tick_handlers = {}
|
2018-04-07 01:24:16 +02:00
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
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
|
|
|
|
)
|
2017-06-13 13:16:07 +02:00
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
local function remove(tbl, handler)
|
2019-01-06 22:58:43 +02:00
|
|
|
if tbl == nil then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
-- 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
|
2018-04-06 21:57:58 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-06-13 13:16:07 +02:00
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
--- 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 EventCore.runtime then
|
|
|
|
error('Calling Event.add after on_init() or on_load() has run is a desync risk.', 2)
|
|
|
|
end
|
2017-06-13 13:16:07 +02:00
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
core_add(event_name, handler)
|
2018-04-06 21:57:58 +02:00
|
|
|
end
|
2017-06-13 13:16:07 +02:00
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
--- 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 EventCore.runtime then
|
|
|
|
error('Calling Event.on_init after on_init() or on_load() has run is a desync risk.', 2)
|
|
|
|
end
|
2017-06-13 13:16:07 +02:00
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
core_on_init(handler)
|
2017-06-13 13:16:07 +02:00
|
|
|
end
|
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
--- 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 EventCore.runtime then
|
|
|
|
error('Calling Event.on_load after on_init() or on_load() has run is a desync risk.', 2)
|
2018-04-06 21:57:58 +02:00
|
|
|
end
|
2018-12-28 18:21:45 +02:00
|
|
|
|
|
|
|
core_on_load(handler)
|
2018-04-06 21:57:58 +02:00
|
|
|
end
|
2017-06-13 13:16:07 +02:00
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
--- 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 EventCore.runtime then
|
|
|
|
error('Calling Event.on_nth_tick after on_init() or on_load() has run is a desync risk.', 2)
|
2018-04-06 21:57:58 +02:00
|
|
|
end
|
2018-12-28 18:21:45 +02:00
|
|
|
|
|
|
|
core_on_nth_tick(tick, handler)
|
2018-04-06 21:57:58 +02:00
|
|
|
end
|
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
--- Register a token handler that can be safely added and removed at runtime.
|
2019-01-06 22:58:43 +02:00
|
|
|
-- Do NOT call this method during on_load.
|
2018-12-28 18:21:45 +02:00
|
|
|
-- 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
|
|
|
|
|
|
|
|
local tokens = token_handlers[event_name]
|
|
|
|
if not tokens then
|
|
|
|
token_handlers[event_name] = {token}
|
2018-04-06 21:57:58 +02:00
|
|
|
else
|
2018-12-28 18:21:45 +02:00
|
|
|
tokens[#tokens + 1] = token
|
|
|
|
end
|
|
|
|
|
2019-01-03 19:23:41 +02:00
|
|
|
if handlers_added then
|
2018-12-28 18:21:45 +02:00
|
|
|
local handler = Token.get(token)
|
|
|
|
core_add(event_name, handler)
|
2018-04-06 21:57:58 +02:00
|
|
|
end
|
|
|
|
end
|
2017-06-13 13:16:07 +02:00
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
--- Removes a token handler for the given event_name.
|
2019-01-06 22:58:43 +02:00
|
|
|
-- Do NOT call this method during on_load.
|
2018-12-28 18:21:45 +02:00
|
|
|
-- 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)
|
|
|
|
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)
|
2018-04-06 21:57:58 +02:00
|
|
|
end
|
2017-06-13 13:16:07 +02:00
|
|
|
end
|
2018-04-06 21:57:58 +02:00
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
--- 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.
|
2019-01-06 22:58:43 +02:00
|
|
|
-- Do NOT call this method during on_load.
|
2018-12-28 18:21:45 +02:00
|
|
|
-- 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 type(func) ~= 'function' then
|
|
|
|
error('func must be a function', 2)
|
|
|
|
end
|
2018-04-07 01:24:16 +02:00
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
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
|
2018-05-20 17:28:33 +02:00
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
local funcs = function_handlers[event_name]
|
|
|
|
if not funcs then
|
|
|
|
function_handlers[event_name] = {func}
|
2018-04-07 01:24:16 +02:00
|
|
|
else
|
2018-12-28 18:21:45 +02:00
|
|
|
funcs[#funcs + 1] = func
|
2018-04-07 01:24:16 +02:00
|
|
|
end
|
2018-05-20 17:28:33 +02:00
|
|
|
|
2019-01-03 19:23:41 +02:00
|
|
|
if handlers_added then
|
2018-12-28 18:21:45 +02:00
|
|
|
core_add(event_name, func)
|
2018-04-07 01:24:16 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
--- Removes a handler for the given event_name.
|
2019-01-06 22:58:43 +02:00
|
|
|
-- Do NOT call this method during on_load.
|
2018-12-28 18:21:45 +02:00
|
|
|
-- 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)
|
|
|
|
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)
|
2018-04-07 01:24:16 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
--- Register a token handler for the nth tick that can be safely added and removed at runtime.
|
2019-01-06 22:58:43 +02:00
|
|
|
-- Do NOT call this method during on_load.
|
2018-12-28 18:21:45 +02:00
|
|
|
-- See documentation at top of file for details on using events.
|
|
|
|
-- @param event_name<number>
|
|
|
|
-- @param token<number>
|
|
|
|
function Event.add_removable_nth_tick(tick, token)
|
|
|
|
if type(token) ~= 'number' then
|
|
|
|
error('token must be a number', 2)
|
|
|
|
end
|
2018-05-20 17:28:33 +02:00
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
local tokens = token_nth_tick_handlers[tick]
|
|
|
|
if not tokens then
|
|
|
|
token_nth_tick_handlers[tick] = {token}
|
|
|
|
else
|
|
|
|
tokens[#tokens + 1] = token
|
|
|
|
end
|
|
|
|
|
2019-01-03 19:23:41 +02:00
|
|
|
if handlers_added then
|
2018-12-28 18:21:45 +02:00
|
|
|
local handler = Token.get(token)
|
|
|
|
core_on_nth_tick(tick, handler)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Removes a token handler for the nth tick.
|
2019-01-06 22:58:43 +02:00
|
|
|
-- Do NOT call this method during on_load.
|
2018-12-28 18:21:45 +02:00
|
|
|
-- See documentation at top of file for details on using events.
|
|
|
|
-- @param event_name<number>
|
|
|
|
-- @param token<number>
|
|
|
|
function Event.remove_removable_nth_tick(tick, token)
|
|
|
|
local tokens = token_nth_tick_handlers[tick]
|
2018-05-20 17:28:33 +02:00
|
|
|
|
2018-04-07 01:24:16 +02:00
|
|
|
if not tokens then
|
|
|
|
return
|
|
|
|
end
|
2018-05-20 17:28:33 +02:00
|
|
|
|
2018-04-07 01:24:16 +02:00
|
|
|
local handler = Token.get(token)
|
2018-12-28 18:21:45 +02:00
|
|
|
local handlers = on_nth_tick_event_handlers[tick]
|
2018-05-20 17:28:33 +02:00
|
|
|
|
2018-04-07 01:24:16 +02:00
|
|
|
remove(tokens, token)
|
|
|
|
remove(handlers, handler)
|
2018-05-20 17:28:33 +02:00
|
|
|
|
2018-04-07 01:24:16 +02:00
|
|
|
if #handlers == 0 then
|
2018-12-28 18:21:45 +02:00
|
|
|
script.on_nth_tick(tick, nil)
|
2018-04-07 01:24:16 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
--- 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.
|
2019-01-06 22:58:43 +02:00
|
|
|
-- Do NOT call this method during on_load.
|
2018-12-28 18:21:45 +02:00
|
|
|
-- See documentation at top of file for details on using events.
|
|
|
|
-- @param event_name<number>
|
|
|
|
-- @param func<function>
|
|
|
|
function Event.add_removable_nth_tick_function(tick, func)
|
|
|
|
if type(func) ~= 'function' then
|
|
|
|
error('func must be a function', 2)
|
|
|
|
end
|
2018-04-07 01:24:16 +02:00
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
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
|
|
|
|
|
2019-01-03 19:23:41 +02:00
|
|
|
if handlers_added then
|
2018-12-28 18:21:45 +02:00
|
|
|
core_on_nth_tick(tick, func)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Removes a handler for the nth tick.
|
2019-01-06 22:58:43 +02:00
|
|
|
-- Do NOT call this method during on_load.
|
2018-12-28 18:21:45 +02:00
|
|
|
-- See documentation at top of file for details on using events.
|
|
|
|
-- @param event_name<number>
|
|
|
|
-- @param func<function>
|
|
|
|
function Event.remove_removable_nth_tick_function(tick, func)
|
|
|
|
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
|
2018-05-20 17:28:33 +02:00
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
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)
|
2018-04-07 01:24:16 +02:00
|
|
|
end
|
|
|
|
end
|
2019-01-03 19:23:41 +02:00
|
|
|
|
|
|
|
handlers_added = true
|
2018-04-07 01:24:16 +02:00
|
|
|
end
|
|
|
|
|
2018-12-28 18:21:45 +02:00
|
|
|
core_on_init(add_handlers)
|
|
|
|
core_on_load(add_handlers)
|
2018-04-07 01:24:16 +02:00
|
|
|
|
2017-06-13 13:16:07 +02:00
|
|
|
return Event
|