[added] pubsub and timer modules

This commit is contained in:
Max Cahill 2021-03-12 21:23:54 +11:00
parent 16c183ec31
commit 89ad4c2dda
4 changed files with 126 additions and 0 deletions

View File

@ -31,6 +31,8 @@ local _batteries = {
vec3 = require_relative("vec3"), vec3 = require_relative("vec3"),
intersect = require_relative("intersect"), intersect = require_relative("intersect"),
-- --
timer = require_relative("timer"),
pubsub = require_relative("pubsub"),
unique_mapping = require_relative("unique_mapping"), unique_mapping = require_relative("unique_mapping"),
state_machine = require_relative("state_machine"), state_machine = require_relative("state_machine"),
async = require_relative("async"), async = require_relative("async"),
@ -73,6 +75,9 @@ function _batteries:export()
--overwrite assert wholesale (it's compatible) --overwrite assert wholesale (it's compatible)
assert = self.assert assert = self.assert
--export the whole library to global `batteries`
batteries = self
return self return self
end end

60
pubsub.lua Normal file
View File

@ -0,0 +1,60 @@
--[[
dead-simple publish-subscribe message bus
]]
local path = (...):gsub("pubsub", "")
local class = require(path .. "class")
local pubsub = class()
--create a new pubsub bus
function pubsub:new()
return self:init({
subscriptions = {},
})
end
--(internal; notify a callback set of an event)
function pubsub:_notify(callbacks, ...)
if callbacks then
for _, f in callbacks:ipairs() do
f(...)
end
end
end
--publish an event, with optional arguments
--notifies both the direct subscribers, and those subscribed to "everything"
function pubsub:publish(event, ...)
self:_notify(self.subscriptions[event], ...)
self:_notify(self.subscriptions.everything, event, ...)
end
--subscribe to an event
--can be a specifically named event, or "everything" to get notified for any event
--for "everything", the callback will recieve the event name as the first argument
function pubsub:subscribe(event, callback)
local callbacks = self.subscriptions[event]
if not callbacks then
callbacks = set()
self.subscriptions[event] = callbacks
end
callbacks:add(callback)
end
--unsubscribe from an event
function pubsub:unsubscribe(event, callback)
local callbacks = self.subscriptions[event]
if callbacks then
callbacks:remove(callback)
if callbacks:size() == 0 then
self.subscriptions[event] = nil
end
end
end
--check if there is a subscriber for a given event
function pubsub:has_subcriber(event)
return self.subscriptions[event] ~= nil
end
return pubsub

View File

@ -64,6 +64,8 @@ General utility data structures and algorithms to speed you along your way.
- `set` - A set type supporting a full suite of set operations with fast membership testing and `ipairs`-style iteration. - `set` - A set type supporting a full suite of set operations with fast membership testing and `ipairs`-style iteration.
- `sort` - Provides a stable merge+insertion sorting algorithm that is also, as a bonus, often faster than `table.sort` under luajit. Also exposes `insertion_sort` if needed. Alias `stable_sort`. - `sort` - Provides a stable merge+insertion sorting algorithm that is also, as a bonus, often faster than `table.sort` under luajit. Also exposes `insertion_sort` if needed. Alias `stable_sort`.
- `state_machine` - Finite state machine implementation with state transitions and all the rest. Useful for game states, AI, cutscenes... - `state_machine` - Finite state machine implementation with state transitions and all the rest. Useful for game states, AI, cutscenes...
- `timer` - a "countdown" style timer with progress and completion callbacks.
- `pubsub` - a self-contained publish/subscribe message bus. Immediate mode rather than queued, local rather than networked, but if you were expecting mqtt in 60 lines I don't know what to tell you. Scales pretty well nonetheless.
**Geometry:** **Geometry:**

59
timer.lua Normal file
View File

@ -0,0 +1,59 @@
--[[
basic timer class
can check for expiry and register a callback to be called on progress and on finish
if you find yourself using lots of these for pushing stuff into the future,
look into async.lua and see if it might be a better fit!
]]
local path = (...):gsub("timer", "")
local class = require(path .. "class")
local timer = class()
--create a timer, with optional callbacks
--callbacks recieve as arguments:
-- the current progress as a number from 0 to 1, so can be used for lerps
-- the timer object, so can be reset if needed
function timer:new(time, on_progress, on_finish)
return self:init({
time = math.max(time, 1e-6), --negative time not allowed
timer = 0,
on_progress = on_progress,
on_finish = on_finish,
})
end
--update this timer, calling the relevant callback if it exists
function timer:update(dt)
if not self:expired() then
self.timer = self.timer + dt
--get the relevant callback
local cb = self:expired()
and self.on_finish
or self.on_progress
if cb then
cb(self:progress(), self)
end
end
end
--check if the timer has expired
function timer:expired()
return self.timer >= self.time
end
--get the timer's progress from 0 to 1
function timer:progress()
return math.min(self.timer / self.time, 1)
end
--reset the timer
--will resume calling the same callbacks, so can be used for intervals
function timer:reset()
self.timer = 0
end
return timer