--- Event module -- @module Event require 'stdlib/core' require 'stdlib/game' Event = { _registry = {}, core_events = { init = -1, load = -2, configuration_changed = -3, _register = function(id) if id == Event.core_events.init then script.on_init(function() Event.dispatch({name = Event.core_events.init, tick = game.tick}) end) elseif id == Event.core_events.load then script.on_load(function() Event.dispatch({name = Event.core_events.load, tick = -1}) end) elseif id == Event.core_events.configuration_changed then script.on_configuration_changed(function(data) Event.dispatch({name = Event.core_events.configuration_changed, tick = game.tick, data = data}) end) end end } } --- Registers a function for a given event -- @param event or array containing events to register -- @param handler Function to call when event is triggered -- @return #Event function Event.register(event, handler) fail_if_missing(event, "missing event argument") if type(event) == "number" then event = {event} end for _, event_id in pairs(event) do fail_if_missing(event_id, "missing event id") if handler == nil then Event._registry[event_id] = nil script.on_event(event_id, nil) else if not Event._registry[event_id] then Event._registry[event_id] = {} if event_id >= 0 then script.on_event(event_id, Event.dispatch) else Event.core_events._register(event_id) end end table.insert(Event._registry[event_id], handler) end end return Event end --- Calls the registerd handlers -- @param event LuaEvent as created by game.raise_event function Event.dispatch(event) fail_if_missing(event, "missing event argument") if Event._registry[event.name] then for _, handler in pairs(Event._registry[event.name]) do local metatbl = { __index = function(tbl, key) if key == '_handler' then return handler else return rawget(tbl, key) end end } setmetatable(event, metatbl) local success, err = pcall(handler, event) if not success then -- may be nil in on_load if _G.game then if Game.print_all(err) == 0 then -- no players received the message, force a real error so someone notices error(err) end else -- no way to handle errors cleanly when the game is not up error(err) end return end if err then return end end end end --- Removes the handler from the event -- @param event event or array containing events to remove the handler -- @param handler to remove -- @return #Event function Event.remove(event, handler) fail_if_missing(event, "missing event argument") fail_if_missing(handler, "missing handler argument") if type(event) == "number" then event = {event} end for _, event_id in pairs(event) do fail_if_missing(event_id, "missing event id") if Event._registry[event_id] then for i=#Event._registry[event_id], 1, -1 do if Event._registry[event_id][i] == handler then table.remove(Event._registry[event_id], i) end end if #Event._registry[event_id] == 0 then Event._registry[event_id] = nil script.on_event(event_id, nil) end end end return Event end return Event