Currently I’m making a event system that matches the roblox event system. I currently have this:
return function()
local Event = BaseClass:new("Event")
local Connection = BaseClass:new("Connection")
local Log = import("org.log4lua.Log")()
local EventLogger = Log:getLogger(Event)
local Connection = Log:getLogger(Connection)
Event.Event = function(self)
self.functions = { }
return self
end
Event.Connect = function(self, connectionFunction)
if (not self.functions) then
return EventLogger:atError()
:log("Attempted to connect to a invalid event")
end
self.functions[connectionFunction] = connectionFunction
return Connection(self, Connection)
end
Event.Fire = function(self, ...)
for _, connectionFunction in pairs(self.functions) do
connectionFunction(...)
end
end
Connection.Connection = function(self, event, connectionFunction)
self.event = event
self.connectionFunction = connectionFunction
return self
end
Connection.Disconnect = function(self)
self.event.functions[self.connectionFunction] = nil
end
return Event
end
(Ignore all the class based stuff)
I have the async side of calling the function for events but I wanted to implement :wait() as well. I don’t want to have to go to something like:
repeat wait() until eventFired
as this creates unnecessary performance loss and hogs CPU. Any help is appreciated!
It’s not very easy to do. In fact, the way I’ve ended up doing it is by using the Event:Wait() method of a BindableEvent. Here’s my custom Event class:
Well thats one way to fix it! I would like to have testing with Lemur and since it doesn’t have support for this I would like to put this off to last resort. I’m now wondering if roblox is handling this C sided or do they have a pure lua implmentation of this?
I imagine it simply yields the current thread/coroutine behind the scenes. You can replicate this using coroutine yielding and such, but you will lose your stack traces in the process, which is a huge pain in regards to debugging.
To do this without touching BindableEvents: return a call to coroutine.yield from the Wait method. Before you yield, add the current thread (found with coroutine.running) to an array of threads associated with the event that need to be resumed upon the event being fired:
function Event:Wait()
-- add current thread to array
table.insert(self.Threads, coroutine.running())
-- yield thread until it is resumed by Event:Fire, and return arguments passed to Fire
return coroutine.yield()
end
function Event:Fire(...)
-- invoke listeners here...
-- then, iterate through each yielding thread and resume it:
for _, thread in ipairs(self.Threads) do
coroutine.resume(thread, ...)
end
-- clear/replace the Threads table
self.Threads = {}
end