Simple module that is based on Roblox’s events, but uses ‘keys’ instead of classes, supports timeouts in the :Await
method and you can pass arguments to the callback from inside the :Subscribe
method, making it easier to use a single function for multiple subscriptions
Demo:
local Event = require(game.ReplicatedStorage.Event)
local TestEvent = Event.new()
local function Test(...)
print(...)
end
TestEvent:Subscribe("TestKey", Test, "Subscription One")
TestEvent:Subscribe("TestKey2", Test, "Subscription Two")
TestEvent:Fire("Fire")
delay(3, function() TestEvent:Fire() end)
print("Waiting")
TestEvent:Await()
print("Waited")
print("Waiting again")
TestEvent:Await(2)
print("Timed out after 2 seconds")
TestEvent:Unsubscribe("TestKey2")
TestEvent:Fire()
--If you dont care what the key is, pass nil and the method will return the key attached to the subscription
local Key = TestEvent:Subscribe(nil, Test, "No key given to this one")
TestEvent:Fire()
TestEvent:Unsubscribe(Key)
TestEvent:Fire()
Event.lua (1.8 KB)
Lua source
local Class = {}
Class.__index = Class
function Class.new()
return setmetatable({}, Class)
end
function Class:Fire(...)
if (self.Subscriptions) then
for _, Subscription in pairs(self.Subscriptions) do
if (Subscription.Arguments) then
coroutine.wrap(Subscription.Callback)(unpack(Subscription.Arguments), ...)
else
coroutine.wrap(Subscription.Callback)(...)
end
end
end
if (self.Threads) then
for Key = #self.Threads, 1, -1 do
local Thread = self.Threads[Key]
if (Thread) then
table.remove(self.Threads, Key)
coroutine.resume(Thread, ...)
end
end
if (not next(self.Threads)) then
self.Threads = nil
end
end
end
function Class:Subscribe(Key, Callback, ...)
if (not self.Subscriptions) then
self.Subscriptions = {}
end
if (not Key) then
if (not self.UID) then
self.UID = 0
end
Key = tostring(self.UID)
self.UID = self.UID + 1
end
self.Subscriptions[Key] = {Key = Key, Callback = Callback, Arguments = (... and {...} or nil)}
return Key, self.Subscriptions[Key]
end
function Class:Unsubscribe(Key)
if (not self.Subscriptions or not self.Subscriptions[Key]) then return end
self.Subscriptions[Key] = nil
if (not next(self.Subscriptions)) then
self.Subscriptions = nil
end
end
function Class:Await(Timeout)
if (not self.Threads) then
self.Threads = {}
end
local Thread = coroutine.running()
table.insert(self.Threads, Thread)
if (Timeout) then
delay(Timeout, function()
if (not Thread) then return end
local Index = (self.Threads and table.find(self.Threads, Thread))
if (Index) then
table.remove(self.Threads, Index)
end
coroutine.resume(Thread)
end)
end
coroutine.yield()
Thread = nil
end
return Class