[Library] lib-events v1

Place to post guides, observations, things related to modding that are not mods themselves.
Post Reply
folk
Long Handed Inserter
Long Handed Inserter
Posts: 96
Joined: Fri Mar 03, 2017 5:00 pm
Contact:

[Library] lib-events v1

Post by folk »

So while making lib-reset, zx64 lamented that we can't use strings as event IDs, and so I tried to make this library just for fun - and I can't find any faults with it.

Please refrain from releasing your own version of this library under the same name (though obviously the license allows you to do whatever you want); let's keep it to this thread, and number the versions accordingly.
If anyone wants to set up an official github repository, then that would be excellent.

Code: Select all

-- Version 1 by folk
-- To the extent possible under law, the authors have waived all copyright and related or neighboring rights to lib-events.lua.
-- http://creativecommons.org/publicdomain/zero/1.0/
-- In laymans terms: "do whatever you want with this file and its content"
-- Credits: folk, zx64
--[[

USAGE INSTRUCTIONS
In your control.lua scope somewhere, put something to the effect of
local events = require("lib-events")

Fire/trigger events with any arbitrary number of arguments:
events.trigger("your-event-name", player.index, false, "arbitrary/foo", 123, tech.name, {foo=false}, ...)

Register event handlers with:
events.register("your-event-name", function(event)
	local playerIndex, myBool, arbString, counter, techName, dataTable = unpack(event)
	print(serpent.block(event))
end)

Other mods can listen for "your-event-name" before or after you, irrespective of mod load order or dependencies.

Events that are triggered, but have zero listeners, will not actually be triggered. Of course, noone will notice.
]]

local MAJOR, MINOR, register = "lib-events", 1, true
local eventIds
if remote.interfaces[MAJOR] then
	local existingIds = remote.call(MAJOR, "getEventIds")
	if type(existingIds) ~= "nil" then eventIds = existingIds
	else error("Previous version of lib-events did not pass on the registered event IDs.") end
	local version = remote.call(MAJOR, "version")
	if type(version) == "number" and version <= MINOR then register = false
	else
		remote.remove_interface(MAJOR)
		print("More recent version of lib-events has been detected.")
	end
end
if register then
	if type(eventIds) ~= "table" then eventIds = {} end
	local function getId(name)
		if not eventIds[name] then eventIds[name] = script.generate_event_name() end
		return eventIds[name]
	end
	local function trigger(name, ...)
		if not eventIds[name] then return end
		script.raise_event(eventIds[name], {...})
	end
	remote.add_interface(MAJOR, {
		getId=getId,
		trigger=trigger,
		version=function() return MINOR end,
		getEventIds=function() return eventIds end,
	})
end
local m = {
	trigger = function(...) remote.call(MAJOR, "trigger", ...) end,
	register = function(name, funcref)
		script.on_event((remote.call(MAJOR, "getId", name)), funcref)
	end,
}
return m
hastebin.com raw text: https://hastebin.com/raw/evuravanus.lua
hastebin.com syntax highlighted lua: https://hastebin.com/evuravanus.lua

The library, as you can see, is in the public domain, so anyone can just drop it in their package and register with it.
If the library exists in more than one addon, all addons that use it get automatically upgraded to the highest version found.
The overhead from using it is insignificant for most uses, but obviously if you fire tons of events every tick, anything will have an impact.

I don't know what is the usecase for this library, or whether it improves on addons using the remote interface directly in any way. I just made it for fun, hopefully someone else can find out how it's useful.

To reiterate from the code-block above, here is how you use it;
1. Put the code in a file called lib-events.lua in your addon
2. Put this somewhere near the top local events = require("lib-events")
3. Trigger any event you want with events.trigger("my-mod-your-event-name", player.index, false, "arbitrary/foo", 123, tech.name, {foo=false}, ...)
4. Catch events with
events.register("my-mod-your-event-name", function(event)
local playerIndex, myBool, arbString, counter, techName, dataTable = unpack(event)
print(serpent.block(event))
end)

Triggered events that noone listens for have no overhead except the parsing of the parameters like any function call.
Registered event handlers for event names/ids that are never triggered have no overhead except the initial setup and memory cost of the function.

1. Any arbitrary addon can trigger/catch any event from any other arbitrary addon, no matter the load order of the mods.
2. Event names/IDs are not unique; any addon can trigger and catch any event name they want.
3. There is no way to determine which addon triggered an event.
Those three "negatives" are not really negatives, they are exactly how I would expect an event library like this to behave.

Anyway, I hope someone finds it useful.

EDITS:
1: 02.05.17: Added link to lib-reset thread.

Post Reply

Return to “Modding discussion”