Skip to content

Commit 5c44054

Browse files
committed
Merge branch 'development'
2 parents 7c73f9b + 3b95427 commit 5c44054

File tree

9 files changed

+3295
-2515
lines changed

9 files changed

+3295
-2515
lines changed

AutomaticUpdating.lua

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,19 @@ if NewTool then
5757
script.Parent = nil;
5858
local ToolParent = Tool.Parent;
5959

60-
-- Replace the current tool with the new one
61-
Tool:Destroy();
60+
-- Remove current tool (delayed to prevent parenting conflicts)
61+
wait(0.05);
62+
Tool.Parent = nil;
63+
64+
-- Remove the tool again if anything attempts to reparent it
65+
Tool.Changed:connect(function (Property)
66+
if Property == 'Parent' and Tool.Parent then
67+
wait(0.05);
68+
Tool.Parent = nil;
69+
end;
70+
end);
71+
72+
-- Add the new tool
6273
NewTool.Parent = ToolParent;
6374

6475
end;

BoundingBoxModule.lua

Lines changed: 132 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ local StaticPartMonitors = {};
1212
local RecalculateStaticExtents = true;
1313
local AggregatingStaticParts = false;
1414
local StaticPartAggregators = {};
15+
local PotentialPartMonitors = {};
1516

1617
function BoundingBoxModule.StartBoundingBox(HandleAttachmentCallback)
1718
-- Creates and starts a selection bounding box
@@ -40,12 +41,15 @@ function BoundingBoxModule.StartBoundingBox(HandleAttachmentCallback)
4041
RecalculateStaticExtents = true;
4142
StartAggregatingStaticParts();
4243

44+
-- Store handle attachment callback
45+
BoundingBoxHandleCallback = HandleAttachmentCallback;
46+
4347
-- Begin the bounding box's updater
44-
BoundingBoxUpdater = Support.ScheduleRecurringTask(UpdateBoundingBox, 0.05);
48+
BoundingBoxModule.UpdateBoundingBox();
49+
BoundingBoxUpdater = Support.ScheduleRecurringTask(BoundingBoxModule.UpdateBoundingBox, 0.05);
4550

4651
-- Attach handles if requested
47-
if HandleAttachmentCallback then
48-
BoundingBoxHandleCallback = HandleAttachmentCallback;
52+
if BoundingBoxHandleCallback then
4953
BoundingBoxHandleCallback(BoundingBox);
5054
end;
5155

@@ -59,7 +63,20 @@ function BoundingBoxModule.GetBoundingBox()
5963

6064
end;
6165

62-
function UpdateBoundingBox()
66+
function IsPhysicsStatic()
67+
-- Returns whether the game's physics are active or static
68+
69+
-- Determine value if not yet cached
70+
if _IsPhysicsStatic == nil then
71+
_IsPhysicsStatic = (Core.Mode == 'Plugin') and (Workspace.DistributedGameTime == 0);
72+
end;
73+
74+
-- Return cached value
75+
return _IsPhysicsStatic;
76+
77+
end;
78+
79+
function BoundingBoxModule.UpdateBoundingBox()
6380
-- Updates the bounding box to fit the selection's extents
6481

6582
-- Make sure the bounding box is enabled
@@ -140,24 +157,13 @@ function AddStaticParts(Parts)
140157
for _, Part in pairs(Parts) do
141158

142159
-- Ensure part isn't already indexed, and verify it is static
143-
if not StaticPartsIndex[Part] and Part.Anchored then
160+
if not StaticPartsIndex[Part] and (IsPhysicsStatic() or Part.Anchored) then
144161

145162
-- Add part to static index
146163
StaticPartsIndex[Part] = true;
147164

148-
-- Start monitoring part for changes
149-
StaticPartMonitors[Part] = Part.Changed:connect(function (Property)
150-
151-
-- Trigger static extent recalculations on position or size changes
152-
if Property == 'CFrame' or Property == 'Size' then
153-
RecalculateStaticExtents = true;
154-
155-
-- Remove part from static index if it becomes mobile
156-
elseif Property == 'Anchored' and not Part.Anchored then
157-
RemoveStaticParts { Part };
158-
end;
159-
160-
end);
165+
-- Monitor static part for changes
166+
AddStaticPartMonitor(Part);
161167

162168
end;
163169

@@ -171,6 +177,30 @@ function AddStaticParts(Parts)
171177

172178
end;
173179

180+
function AddStaticPartMonitor(Part)
181+
-- Monitors the given part to track when it is no longer static
182+
183+
-- Ensure part isn't already monitored
184+
if not StaticPartsIndex[Part] then
185+
return;
186+
end;
187+
188+
-- Start monitoring part for changes
189+
StaticPartMonitors[Part] = Part.Changed:connect(function (Property)
190+
191+
-- Trigger static extent recalculations on position or size changes
192+
if Property == 'CFrame' or Property == 'Size' then
193+
RecalculateStaticExtents = true;
194+
195+
-- Remove part from static index if it becomes mobile
196+
elseif Property == 'Anchored' and not IsPhysicsStatic() and not Part.Anchored then
197+
RemoveStaticParts { Part };
198+
end;
199+
200+
end);
201+
202+
end;
203+
174204
function RemoveStaticParts(Parts)
175205
-- Removes the given parts from the static parts index
176206

@@ -203,12 +233,8 @@ function StartAggregatingStaticParts()
203233
AddStaticParts(Core.Selection.Items);
204234

205235
-- Watch for parts that become static
206-
for _, Part in pairs(Core.Selection.Items) do
207-
table.insert(StaticPartAggregators, Part.Changed:connect(function (Property)
208-
if Property == 'Anchored' and Part.Anchored then
209-
AddStaticParts { Part };
210-
end;
211-
end));
236+
for Part in pairs(Core.Selection.ItemIndex) do
237+
AddPotentialPartMonitor(Part);
212238
end;
213239

214240
-- Watch newly selected parts
@@ -219,22 +245,92 @@ function StartAggregatingStaticParts()
219245

220246
-- Watch for parts that become anchored
221247
for _, Part in pairs(Parts) do
222-
table.insert(StaticPartAggregators, Part.Changed:connect(function (Property)
223-
if Property == 'Anchored' and Part.Anchored then
224-
AddStaticParts { Part };
225-
end;
226-
end));
248+
AddPotentialPartMonitor(Part);
227249
end;
228250

229251
end));
230252

231253
-- Remove deselected parts from static parts index
232254
table.insert(StaticPartAggregators, Core.Selection.ItemsRemoved:connect(function (Parts)
233255
RemoveStaticParts(Parts);
256+
for _, Part in pairs(Parts) do
257+
if PotentialPartMonitors[Part] then
258+
PotentialPartMonitors[Part]:disconnect();
259+
PotentialPartMonitors[Part] = nil;
260+
end;
261+
end;
234262
end));
235263

236264
end;
237265

266+
function BoundingBoxModule.RecalculateStaticExtents()
267+
-- Sets flag indicating that extents of static items should be recalculated
268+
269+
-- Set flag to trigger recalculation on the next step in the update loop
270+
RecalculateStaticExtents = true;
271+
272+
end;
273+
274+
function AddPotentialPartMonitor(Part)
275+
-- Monitors the given part to track when it becomes static
276+
277+
-- Ensure part is not already monitored
278+
if PotentialPartMonitors[Part] then
279+
return;
280+
end;
281+
282+
-- Create anchored state change monitor
283+
PotentialPartMonitors[Part] = Part.Changed:connect(function (Property)
284+
if Property == 'Anchored' and Part.Anchored then
285+
AddStaticParts { Part };
286+
end;
287+
end);
288+
289+
end;
290+
291+
function BoundingBoxModule.PauseMonitoring()
292+
-- Disables part monitors
293+
294+
-- Disconnect all potential part monitors
295+
for Part, Monitor in pairs(PotentialPartMonitors) do
296+
Monitor:disconnect();
297+
PotentialPartMonitors[Part] = nil;
298+
end;
299+
300+
-- Disconnect all static part monitors
301+
for Part, Monitor in pairs(StaticPartMonitors) do
302+
Monitor:disconnect();
303+
StaticPartMonitors[Part] = nil;
304+
end;
305+
306+
-- Stop update loop
307+
if BoundingBoxUpdater then
308+
BoundingBoxUpdater:Stop();
309+
BoundingBoxUpdater = nil;
310+
end;
311+
312+
end;
313+
314+
function BoundingBoxModule.ResumeMonitoring()
315+
-- Starts update loop and part monitors for selected and indexed parts
316+
317+
-- Start static part monitors
318+
for StaticPart in pairs(StaticPartsIndex) do
319+
AddStaticPartMonitor(StaticPart);
320+
end;
321+
322+
-- Start potential part monitors
323+
for Part in pairs(Core.Selection.ItemIndex) do
324+
AddPotentialPartMonitor(Part);
325+
end;
326+
327+
-- Start update loop
328+
if not BoundingBoxUpdater then
329+
BoundingBoxUpdater = Support.ScheduleRecurringTask(BoundingBoxModule.UpdateBoundingBox, 0.05);
330+
end;
331+
332+
end;
333+
238334
function StopAggregatingStaticParts()
239335
-- Stops looking for static parts, clears unnecessary data
240336

@@ -250,6 +346,12 @@ function StopAggregatingStaticParts()
250346
StaticPartMonitors[MonitorKey] = nil;
251347
end;
252348

349+
-- Remove all potential part monitors
350+
for MonitorKey, Monitor in pairs(PotentialPartMonitors) do
351+
Monitor:disconnect();
352+
PotentialPartMonitors[MonitorKey] = nil;
353+
end;
354+
253355
-- Clear all static part information
254356
StaticParts = {};
255357
StaticPartsIndex = {};
@@ -283,7 +385,7 @@ function BoundingBoxModule.CalculateExtents(Items, StaticExtents, ExtentsOnly)
283385
for _, Part in pairs(Items) do
284386

285387
-- Avoid re-calculating for static parts
286-
if not (Part.Anchored and StaticExtents) then
388+
if not ((IsPhysicsStatic() or Part.Anchored) and StaticExtents) then
287389

288390
-- Get shortcuts to part data
289391
local PartCFrame = Part.CFrame;

Components/NotificationsManager.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ function Component.Start(Core)
1515
-- Display update notification if tool is outdated
1616
if Core.IsVersionOutdated() then
1717
if Core.Mode == 'Plugin' then
18-
Cheer(View.ToolUpdateNotification).Start(Component.AdjustLayout);
19-
elseif Core.Mode == 'Tool' then
2018
Cheer(View.PluginUpdateNotification).Start(Component.AdjustLayout);
19+
elseif Core.Mode == 'Tool' then
20+
Cheer(View.ToolUpdateNotification).Start(Component.AdjustLayout);
2121
end;
2222
end;
2323

Core.lua

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,13 @@ function Disable()
205205

206206
-- Reenable mouse lock option in tool mode
207207
if Mode == 'Tool' then
208-
SyncAPI:Invoke('SetMouseLockEnabled', true);
208+
pcall(SyncAPI.Invoke, SyncAPI, 'SetMouseLockEnabled', true);
209209
end;
210210

211211
-- Hide UI
212-
UI.Parent = script;
212+
if UI then
213+
UI.Parent = script;
214+
end;
213215

214216
-- Unequip current tool
215217
if CurrentTool then
@@ -222,6 +224,18 @@ function Disable()
222224

223225
end;
224226

227+
228+
-- Core connections
229+
Connections = {};
230+
231+
function ClearConnections()
232+
-- Clears and disconnects temporary connections
233+
for Index, Connection in pairs(Connections) do
234+
Connection:disconnect();
235+
Connections[Index] = nil;
236+
end;
237+
end;
238+
225239
function InitializeUI()
226240
-- Sets up the UI
227241

@@ -294,17 +308,18 @@ elseif Mode == 'Tool' then
294308
Tool.Equipped:connect(Enable);
295309
Tool.Unequipped:connect(Disable);
296310

297-
end;
311+
-- Disable the tool if not parented
312+
if not Tool.Parent then
313+
Disable();
314+
end;
298315

299-
-- Core connections
300-
Connections = {};
316+
-- Disable the tool automatically if not equipped or in backpack
317+
Tool.AncestryChanged:connect(function (Item, Parent)
318+
if not Parent or not (Parent:IsA 'Backpack' or (Parent:IsA 'Model' and Players:GetPlayerFromCharacter(Parent))) then
319+
Disable();
320+
end;
321+
end);
301322

302-
function ClearConnections()
303-
-- Clears and disconnects temporary connections
304-
for Index, Connection in pairs(Connections) do
305-
Connection:disconnect();
306-
Connections[Index] = nil;
307-
end;
308323
end;
309324

310325
-- Assign hotkeys for undoing (left or right shift + Z)

0 commit comments

Comments
 (0)