Skip to content

Commit 44c16ac

Browse files
committed
Merge branch 'development' into main
2 parents 8cdcafd + 0cc06c8 commit 44c16ac

4 files changed

Lines changed: 111 additions & 43 deletions

File tree

docs/changelog.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
## [2.2.1] - May 7 2021
1+
## [2.2.2] - June 4 2021
2+
### Improved
3+
- The accounting of character parts when removed/added via systems like HumanoidDescriptions.
4+
5+
6+
7+
--------
8+
## [2.2.1] - May 21 2021
29
### Added
310
- Compatibility for Deferred Events
411

src/Zone/Signal.lua

Lines changed: 57 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
1-
--[[
2-
This is a simplified version of Quenty's Nevemore Signal Class.
3-
I've stripped this down for improved traceback debugging as I don't mind if the table received is not the same which was passed.
4-
If passing the same table is important for you, see: https://github.com/Quenty/NevermoreEngine/blob/a98f213bb46a3c1dbe311b737689c5cc820a4901/Modules/Shared/Events/Signal.lua
5-
--]]
6-
7-
8-
1+
local HttpService = game:GetService("HttpService")
2+
local RunService = game:GetService("RunService")
3+
local heartbeat = RunService.Heartbeat
94
local Signal = {}
105
Signal.__index = Signal
116
Signal.ClassName = "Signal"
@@ -14,67 +9,95 @@ Signal.totalConnections = 0
149

1510

1611
-- CONSTRUCTOR
17-
function Signal.new(trackConnectionsChanged)
12+
function Signal.new(createConnectionsChangedSignal)
1813
local self = setmetatable({}, Signal)
19-
20-
self._bindableEvent = Instance.new("BindableEvent")
21-
if trackConnectionsChanged then
14+
15+
if createConnectionsChangedSignal then
2216
self.connectionsChanged = Signal.new()
2317
end
2418

19+
self.connections = {}
20+
self.totalConnections = 0
21+
self.waiting = {}
22+
self.totalWaiting = 0
23+
2524
return self
2625
end
2726

2827

2928

3029
-- METHODS
3130
function Signal:Fire(...)
32-
self._bindableEvent:Fire(...)
31+
for _, connection in pairs(self.connections) do
32+
connection.Handler(...)
33+
end
34+
if self.totalWaiting > 0 then
35+
local packedArgs = table.pack(...)
36+
for waitingId, _ in pairs(self.waiting) do
37+
self.waiting[waitingId] = packedArgs
38+
end
39+
end
3340
end
41+
Signal.fire = Signal.Fire
3442

3543
function Signal:Connect(handler)
3644
if not (type(handler) == "function") then
3745
error(("connect(%s)"):format(typeof(handler)), 2)
3846
end
3947

40-
local connection = self._bindableEvent.Event:Connect(function(...)
41-
handler(...)
42-
end)
43-
44-
-- If ``true`` is passed for trackConnectionsChanged within the constructor this will track the amount of active connections
48+
local signal = self
49+
local connectionId = HttpService:GenerateGUID(false)
50+
local connection = {}
51+
connection.Connected = true
52+
connection.ConnectionId = connectionId
53+
connection.Handler = handler
54+
self.connections[connectionId] = connection
55+
56+
function connection:Disconnect()
57+
signal.connections[connectionId] = nil
58+
connection.Connected = false
59+
signal.totalConnections -= 1
60+
if signal.connectionsChanged then
61+
signal.connectionsChanged:Fire(-1)
62+
end
63+
end
64+
connection.Destroy = connection.Disconnect
65+
connection.destroy = connection.Disconnect
66+
connection.disconnect = connection.Disconnect
67+
self.totalConnections += 1
4568
if self.connectionsChanged then
46-
self.totalConnections += 1
4769
self.connectionsChanged:Fire(1)
48-
local heartbeatConection
49-
heartbeatConection = game:GetService("RunService").Heartbeat:Connect(function()
50-
if connection.Connected == false then
51-
heartbeatConection:Disconnect()
52-
if self.connectionsChanged then
53-
self.totalConnections -= 1
54-
self.connectionsChanged:Fire(-1)
55-
end
56-
end
57-
end)
5870
end
5971

6072
return connection
6173
end
74+
Signal.connect = Signal.Connect
6275

6376
function Signal:Wait()
64-
local args = self._bindableEvent.Event:Wait()
77+
local waitingId = HttpService:GenerateGUID(false)
78+
self.waiting[waitingId] = true
79+
self.totalWaiting += 1
80+
repeat heartbeat:Wait() until self.waiting[waitingId] ~= true
81+
self.totalWaiting -= 1
82+
local args = self.waiting[waitingId]
83+
self.waiting[waitingId] = nil
6584
return unpack(args)
6685
end
86+
Signal.wait = Signal.Wait
6787

6888
function Signal:Destroy()
69-
if self._bindableEvent then
70-
self._bindableEvent:Destroy()
71-
self._bindableEvent = nil
89+
if self.bindableEvent then
90+
self.bindableEvent:Destroy()
91+
self.bindableEvent = nil
7292
end
7393
if self.connectionsChanged then
7494
self.connectionsChanged:Fire(-self.totalConnections)
7595
self.connectionsChanged:Destroy()
7696
self.connectionsChanged = nil
77-
self.totalConnections = 0
97+
end
98+
self.totalConnections = 0
99+
for connectionId, connection in pairs(self.connections) do
100+
self.connections[connectionId] = nil
78101
end
79102
end
80103
Signal.destroy = Signal.Destroy

src/Zone/VERSION.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
-- v2.2.1
1+
-- v2.2.2

src/Zone/ZoneController.lua

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,33 @@ local heartbeatActions = {
107107
-- CHARACTER HANDLER
108108
-- This enables character data (volume, HumanoidRootParts, etc) to be handled on
109109
-- an event-basis, instead of being retrieved every interval
110-
local function updateCharactersTotalVolume()
110+
local function preventMultiFrameUpdates(func)
111+
-- This prevents the funtion being called twice within a single frame
112+
-- If called more than once, the function will initally be delayed again until the next frame, then all others cancelled
113+
local callsThisFrame = 0
114+
local updatedThisFrame = false
115+
local newFunc = function(...)
116+
callsThisFrame += 1
117+
if not updatedThisFrame then
118+
local args = table.pack(...)
119+
coroutine.wrap(function()
120+
heartbeat:Wait()
121+
updatedThisFrame = false
122+
if callsThisFrame > 1 then
123+
callsThisFrame = 1
124+
return func(unpack(args))
125+
end
126+
callsThisFrame = 0
127+
end)()
128+
updatedThisFrame = true
129+
return func(...)
130+
end
131+
end
132+
return newFunc
133+
end
134+
135+
local updateCharactersTotalVolume
136+
updateCharactersTotalVolume = preventMultiFrameUpdates(function()
111137
charactersTotalVolume = 0
112138
bodyParts = {}
113139
-- We ignore these due to their insignificance (e.g. we ignore the lower and
@@ -131,13 +157,21 @@ local function updateCharactersTotalVolume()
131157
for _, part in pairs(plr.Character:GetChildren()) do
132158
if part:IsA("BasePart") and not bodyPartsToIgnore[part.Name] then
133159
table.insert(bodyParts, part)
160+
local connection
161+
connection = part:GetPropertyChangedSignal("Parent"):Connect(function()
162+
if part.Parent == nil then
163+
connection:Disconnect()
164+
updateCharactersTotalVolume()
165+
end
166+
end)
134167
end
135168
end
136169
end
137170
end
138-
end
139-
players.PlayerAdded:Connect(function(plr)
140-
plr.CharacterAdded:Connect(function(char)
171+
end)
172+
173+
local function playerAdded(player)
174+
player.CharacterAdded:Connect(function(char)
141175
local humanoid = char:WaitForChild("Humanoid", 3)
142176
if humanoid then
143177
updateCharactersTotalVolume()
@@ -150,10 +184,14 @@ players.PlayerAdded:Connect(function(plr)
150184
end
151185
end
152186
end)
153-
end)
154-
players.PlayerRemoving:Connect(function(plr)
187+
end
188+
players.PlayerAdded:Connect(playerAdded)
189+
for _, player in pairs(players:GetPlayers()) do
190+
playerAdded(player)
191+
end
192+
players.PlayerRemoving:Connect(function(player)
155193
updateCharactersTotalVolume()
156-
playerExitDetections[plr] = nil
194+
playerExitDetections[player] = nil
157195
end)
158196

159197

0 commit comments

Comments
 (0)