-- contact BenSBk if you run into issues or have questions -- data loc

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
-- contact BenSBk if you run into issues or have questions
-- data:
local badType = "bad argument #%i to '%s' (%s expected, got %s)"
local badArgument = "bad argument #%i to '%s' (%s)"
-- Connection:
local Connection = {}
-- constructors:
function Connection.new(listener)
assert(typeof(listener) == "function", badType:format(1, "Connection.new", "function", typeof(listener)))
local connection = setmetatable({}, {__index = Connection})
connection.Listener = listener
return connection
end
-- properties:
Connection.IsConnected = true
-- methods:
function Connection:Disconnect()
self.IsConnected = false
end
-- Signal:
local Signal = {}
-- constructors:
function Signal.new()
local signal = setmetatable({}, {__index = Signal})
signal._Connections = {}
signal._BindableEvent = Instance.new("BindableEvent")
return signal
end
-- methods:
function Signal:Connect(listener)
assert(typeof(listener) == "function", badType:format(1, "Signal:Connect", "function", typeof(listener)))
local connection = Connection.new(listener)
table.insert(self._Connections, connection)
return connection
end
function Signal:Wait()
local temporaryBindableEvent = Instance.new("BindableEvent")
local connection
local results
connection = self:Connect(function(...)
connection:Disconnect()
results = table.pack(...)
temporaryBindableEvent:Fire()
end)
temporaryBindableEvent.Event:Wait()
return table.unpack(results)
end
-- Event:
local Event = {}
-- constructors:
function Event.new()
local event = setmetatable({}, {__index = Event})
event.Signal = Signal.new()
return event
end
-- methods:
function Event:Fire(...)
local signal = self.Signal
local connections = signal._Connections
local threads = signal._Threads
-- removing elements from array while iterating over it is dangerous, safe alternative
local removedConnections = {}
local bindableEvent = signal._BindableEvent
local bindableSignal = bindableEvent.Event
-- pack arguments
local arguments = table.pack(...)
-- iterate over connections, spawning their listener or removing them
for index, connection in ipairs(connections) do
if connection.IsConnected then
-- connect to bindable for preparation of firing
local bindableConnection
bindableConnection = bindableSignal:Connect(function()
bindableConnection:Disconnect()
connection.Listener(table.unpack(arguments))
end)
else
-- add to table of connections to be removed
table.insert(removedConnections, index)
end
end
-- remove connections to be removed
for _, index in ipairs(removedConnections) do
table.remove(connections, index)
end
-- fire bindable, resuming threads and invoking listeners
bindableEvent:Fire()
end
-- PersistentEvent:
local module = {}
function module.Create()
return Event.new()
end
return module