From 3ca541e065557e11bd464ef4e6aae2ca0f2de4ce Mon Sep 17 00:00:00 2001
From: Robert Chiquini
Date: Sat, 8 Apr 2017 21:43:33 -0700
Subject: [PATCH 01/11] Centralize multiselection hotkey detection, add Ctrl
hotkeys
This change turns control of determining whether the tool is in
multiselection mode over to SelectionModule, exposing the current
state through `Selection.Multiselecting`.
Signed-off-by: Robert Chiquini
---
Core.lua | 37 +++++++++++++++++++++++++++++++++++++
SelectionModule.lua | 37 +++++++++++++++++++++++++++++++++++++
TargetingModule.lua | 21 +++++++++------------
tools/Move.lua | 6 +++---
tools/Paint.lua | 4 ++--
tools/Resize.lua | 8 ++++----
tools/Rotate.lua | 4 ++--
7 files changed, 94 insertions(+), 23 deletions(-)
diff --git a/Core.lua b/Core.lua
index 6121b4b..6803be3 100644
--- a/Core.lua
+++ b/Core.lua
@@ -186,6 +186,7 @@ function Enable(Mouse)
EnableHotkeys();
Targeting.EnableTargeting();
Selection.EnableOutlines();
+ Selection.EnableMultiselectionHotkeys();
-- Equip current tool
EquipTool(CurrentTool or require(Tool.Tools.MoveTool));
@@ -304,6 +305,14 @@ AssignHotkey({ 'RightShift', 'Z' }, History.Undo);
AssignHotkey({ 'LeftShift', 'Y' }, History.Redo);
AssignHotkey({ 'RightShift', 'Y' }, History.Redo);
+-- If in-game, enable ctrl hotkeys for undoing and redoing
+if Mode == 'Tool' then
+ AssignHotkey({ 'LeftControl', 'Z' }, History.Undo);
+ AssignHotkey({ 'RightControl', 'Z' }, History.Undo);
+ AssignHotkey({ 'LeftControl', 'Y' }, History.Redo);
+ AssignHotkey({ 'RightControl', 'Y' }, History.Redo);
+end;
+
function CloneSelection()
-- Clones selected parts
@@ -414,6 +423,14 @@ AssignHotkey({ 'RightShift', 'C' }, CloneSelection);
AssignHotkey({ 'LeftShift', 'X' }, DeleteSelection);
AssignHotkey({ 'RightShift', 'X' }, DeleteSelection);
+-- If in-game, enable ctrl hotkeys for cloning and deleting
+if Mode == 'Tool' then
+ AssignHotkey({ 'LeftControl', 'C' }, CloneSelection);
+ AssignHotkey({ 'RightControl', 'C' }, CloneSelection);
+ AssignHotkey({ 'LeftControl', 'X' }, DeleteSelection);
+ AssignHotkey({ 'RightControl', 'X' }, DeleteSelection);
+end;
+
function PrismSelect()
-- Selects parts in the currently selected parts
@@ -465,6 +482,12 @@ end;
AssignHotkey({ 'LeftShift', 'K' }, PrismSelect);
AssignHotkey({ 'RightShift', 'K' }, PrismSelect);
+-- If in-game, enable ctrl hotkeys for prism selection
+if Mode == 'Tool' then
+ AssignHotkey({ 'LeftControl', 'K' }, PrismSelect);
+ AssignHotkey({ 'RightControl', 'K' }, PrismSelect);
+end;
+
function SelectSiblings(ReplaceSelection)
-- Selects all parts under the same parent as the focused part
@@ -494,6 +517,14 @@ AssignHotkey({ 'RightShift', 'LeftBracket' }, Support.Call(SelectSiblings, false
AssignHotkey({ 'LeftShift', 'R' }, Support.Call(Selection.Clear, true));
AssignHotkey({ 'RightShift', 'R' }, Support.Call(Selection.Clear, true));
+-- If in-game, enable ctrl hotkeys for sibling selection & selection clearing
+if Mode == 'Tool' then
+ AssignHotkey({ 'LeftControl', 'LeftBracket' }, Support.Call(SelectSiblings, false));
+ AssignHotkey({ 'RightControl', 'LeftBracket' }, Support.Call(SelectSiblings, false));
+ AssignHotkey({ 'LeftControl', 'R' }, Support.Call(Selection.Clear, true));
+ AssignHotkey({ 'RightControl', 'R' }, Support.Call(Selection.Clear, true));
+end;
+
function IsSelectable(Object)
-- Returns whether `Object` can be selected
@@ -563,6 +594,12 @@ end;
AssignHotkey({ 'LeftShift', 'P' }, ExportSelection);
AssignHotkey({ 'RightShift', 'P' }, ExportSelection);
+-- If in-game, enable ctrl hotkeys for exporting
+if Mode == 'Tool' then
+ AssignHotkey({ 'LeftControl', 'P' }, ExportSelection);
+ AssignHotkey({ 'RightControl', 'P' }, ExportSelection);
+end;
+
function IsVersionOutdated()
-- Returns whether this version of Building Tools is out of date
diff --git a/SelectionModule.lua b/SelectionModule.lua
index c73043e..ed5596c 100644
--- a/SelectionModule.lua
+++ b/SelectionModule.lua
@@ -8,6 +8,7 @@ Selection = {};
Selection.Items = {};
Selection.Outlines = {};
Selection.Color = BrickColor.new 'Cyan';
+Selection.Multiselecting = false;
-- Events to listen to selection changes
Selection.ItemsAdded = RbxUtility.CreateSignal();
@@ -278,6 +279,42 @@ function Selection.EnableOutlines()
end;
+function Selection.EnableMultiselectionHotkeys()
+ -- Enables hotkeys for multiselecting
+
+ -- Determine multiselection hotkeys
+ local Hotkeys = Support.FlipTable { 'LeftShift', 'RightShift', 'LeftControl', 'RightControl' };
+
+ -- Get core API
+ local Core = GetCore();
+
+ -- Listen for matching key presses
+ Core.Connections.MultiselectionHotkeys = Support.AddUserInputListener('Began', 'Keyboard', false, function (Input)
+ if Hotkeys[Input.KeyCode.Name] then
+ Selection.Multiselecting = true;
+ end;
+ end);
+
+ -- Listen for matching key releases
+ Core.Connections.MultiselectingReleaseHotkeys = Support.AddUserInputListener('Ended', 'Keyboard', true, function (Input)
+
+ -- Get currently pressed keys
+ local PressedKeys = Support.GetListMembers(Support.GetListMembers(Game:GetService('UserInputService'):GetKeysPressed(), 'KeyCode'), 'Name');
+
+ -- Continue multiselection if a hotkey is still pressed
+ for _, PressedKey in pairs(PressedKeys) do
+ if Hotkeys[PressedKey] then
+ return;
+ end;
+ end;
+
+ -- Disable multiselection if matching key not found
+ Selection.Multiselecting = false;
+
+ end);
+
+end;
+
function Selection.HideOutlines()
-- Hides selection outlines
diff --git a/TargetingModule.lua b/TargetingModule.lua
index 860f935..ef0e8ec 100644
--- a/TargetingModule.lua
+++ b/TargetingModule.lua
@@ -66,9 +66,6 @@ end;
function TargetingModule.SelectTarget()
- -- Check if shift is held
- local ShiftHeld = Support.AreKeysPressed(Enum.KeyCode.LeftShift) or Support.AreKeysPressed(Enum.KeyCode.RightShift);
-
-- Ensure target selection isn't cancelled
if SelectionCancelled then
SelectionCancelled = false;
@@ -76,7 +73,7 @@ function TargetingModule.SelectTarget()
end;
-- Focus on clicked, selected item
- if not ShiftHeld and Selection.Find(Target) then
+ if not Selection.Multiselecting and Selection.Find(Target) then
Selection.SetFocus(Target);
return;
end;
@@ -87,17 +84,17 @@ function TargetingModule.SelectTarget()
return;
end;
- -- Unselect clicked, selected item if shift is held
- if ShiftHeld and Selection.Find(Target) then
+ -- Unselect clicked, selected item if multiselection is enabled
+ if Selection.Multiselecting and Selection.Find(Target) then
Selection.Remove({ Target }, true);
return;
end;
- -- Add to selection if shift is held
- if ShiftHeld then
+ -- Add to selection if multiselecting
+ if Selection.Multiselecting then
Selection.Add({ Target }, true);
- -- Replace selection if shift is not held
+ -- Replace selection if not multiselecting
else
Selection.Replace({ Target }, true);
end;
@@ -231,11 +228,11 @@ function TargetingModule.FinishRectangleSelecting()
end;
end;
- -- Add to selection if shift is held
- if Support.AreKeysPressed(Enum.KeyCode.LeftShift) or Support.AreKeysPressed(Enum.KeyCode.RightShift) then
+ -- Add to selection if multiselecting
+ if Selection.Multiselecting then
Selection.Add(SelectableItems, true);
- -- Replace selection if shift is not held
+ -- Replace selection if not multiselecting
else
Selection.Replace(SelectableItems, true);
end;
diff --git a/tools/Move.lua b/tools/Move.lua
index f040a0a..4637496 100644
--- a/tools/Move.lua
+++ b/tools/Move.lua
@@ -461,8 +461,8 @@ function BindShortcutKeys()
MoveTool.UI.IncrementOption.Increment.TextBox:CaptureFocus();
end;
- -- Check if the R key was pressed down, and it wasn't Shift R
- elseif InputInfo.KeyCode == Enum.KeyCode.R and not (Support.AreKeysPressed(Enum.KeyCode.LeftShift) or Support.AreKeysPressed(Enum.KeyCode.RightShift)) then
+ -- Check if the R key was pressed down, and it's not the selection clearing hotkey
+ elseif InputInfo.KeyCode == Enum.KeyCode.R and not Selection.Multiselecting then
-- Start tracking snap points nearest to the mouse
StartSnapping();
@@ -718,7 +718,7 @@ function EnableDragging()
end;
-- Make sure this click was not to select
- if Support.AreKeysPressed(Enum.KeyCode.LeftShift) or Support.AreKeysPressed(Enum.KeyCode.RightShift) then
+ if Selection.Multiselecting then
return;
end;
diff --git a/tools/Paint.lua b/tools/Paint.lua
index 54c0b07..a032d56 100644
--- a/tools/Paint.lua
+++ b/tools/Paint.lua
@@ -235,8 +235,8 @@ function BindShortcutKeys()
end;
- -- Check if the R key was pressed
- if InputInfo.KeyCode == Enum.KeyCode.R and not (Support.AreKeysPressed(Enum.KeyCode.LeftShift) or Support.AreKeysPressed(Enum.KeyCode.RightShift)) then
+ -- Check if the R key was pressed, and it wasn't the selection clearing hotkey
+ if InputInfo.KeyCode == Enum.KeyCode.R and not Selection.Multiselecting then
-- Set the current color to that of the current mouse target (if any)
if Core.Mouse.Target then
diff --git a/tools/Resize.lua b/tools/Resize.lua
index 04b876a..d8e8fca 100644
--- a/tools/Resize.lua
+++ b/tools/Resize.lua
@@ -487,8 +487,8 @@ function BindShortcutKeys()
elseif InputInfo.KeyCode == Enum.KeyCode.KeypadSix then
NudgeSelectionByFace(Enum.NormalId.Right);
- -- Start snapping when the R key is pressed down (and it's not Shift R)
- elseif InputInfo.KeyCode == Enum.KeyCode.R and not (Support.AreKeysPressed(Enum.KeyCode.LeftShift) or Support.AreKeysPressed(Enum.KeyCode.RightShift)) then
+ -- Start snapping when the R key is pressed down, and it's not the selection clearing hotkey
+ elseif InputInfo.KeyCode == Enum.KeyCode.R and not Selection.Multiselecting then
StartSnapping();
end;
@@ -513,8 +513,8 @@ function BindShortcutKeys()
return;
end;
- -- Finish snapping when the R key is released (and it's not Shift R)
- if InputInfo.KeyCode == Enum.KeyCode.R and not (Support.AreKeysPressed(Enum.KeyCode.LeftShift) or Support.AreKeysPressed(Enum.KeyCode.RightShift)) then
+ -- Finish snapping when the R key is released, and it's not the selection clearing hotkey
+ if InputInfo.KeyCode == Enum.KeyCode.R and not Selection.Multiselecting then
FinishSnapping();
end;
diff --git a/tools/Rotate.lua b/tools/Rotate.lua
index 800cb4f..51a320f 100644
--- a/tools/Rotate.lua
+++ b/tools/Rotate.lua
@@ -495,8 +495,8 @@ function BindShortcutKeys()
elseif InputInfo.KeyCode == Enum.KeyCode.KeypadSix then
NudgeSelectionByAxis(Enum.Axis.Y, 1);
- -- Start snapping when the R key is pressed down (and it's not Shift R)
- elseif InputInfo.KeyCode == Enum.KeyCode.R and not (Support.AreKeysPressed(Enum.KeyCode.LeftShift) or Support.AreKeysPressed(Enum.KeyCode.RightShift)) then
+ -- Start snapping when the R key is pressed down, and it's not the selection clearing hotkey
+ elseif InputInfo.KeyCode == Enum.KeyCode.R and not Selection.Multiselecting then
StartSnapping();
end;
From 4f8f7d9be1cdf408786c48a0cebccf53ee8a46eb Mon Sep 17 00:00:00 2001
From: Robert Chiquini
Date: Sat, 8 Apr 2017 22:05:37 -0700
Subject: [PATCH 02/11] Fix handle release bugs in Move, Resize, & Rotate tools
When releasing handles from these tools outside of the viewport,
they'd issue an error if you attempted to drag again (due to improper
checks for redundant clean-up operations). This change properly ensures
that clean-up operations are actually necessary.
Signed-off-by: Robert Chiquini
---
tools/Move.lua | 4 ++--
tools/Resize.lua | 10 ++++------
tools/Rotate.lua | 15 +++++----------
3 files changed, 11 insertions(+), 18 deletions(-)
diff --git a/tools/Move.lua b/tools/Move.lua
index 4637496..3f1d6cc 100644
--- a/tools/Move.lua
+++ b/tools/Move.lua
@@ -305,8 +305,8 @@ function AttachHandles(Part, Autofocus)
Connections.HandleRelease = UserInputService.InputEnded:connect(function (InputInfo, GameProcessedEvent)
- -- Make sure this was button 1 being released
- if InputInfo.UserInputType ~= Enum.UserInputType.MouseButton1 then
+ -- Make sure this was button 1 being released, and dragging is ongoing
+ if not HandleDragging or (InputInfo.UserInputType ~= Enum.UserInputType.MouseButton1) then
return;
end;
diff --git a/tools/Resize.lua b/tools/Resize.lua
index d8e8fca..14967ab 100644
--- a/tools/Resize.lua
+++ b/tools/Resize.lua
@@ -292,8 +292,8 @@ function ShowHandles()
Connections.HandleRelease = UserInputService.InputEnded:connect(function (InputInfo, GameProcessedEvent)
- -- Make sure this was button 1 being released
- if InputInfo.UserInputType ~= Enum.UserInputType.MouseButton1 then
+ -- Make sure this was button 1 being released, and handle resizing is ongoing
+ if not HandleResizing or (InputInfo.UserInputType ~= Enum.UserInputType.MouseButton1) then
return;
end;
@@ -304,8 +304,7 @@ function ShowHandles()
Core.Targeting.CancelSelecting();
-- Clear this connection to prevent it from firing again
- Connections.HandleRelease:disconnect();
- Connections.HandleRelease = nil;
+ ClearConnection 'HandleRelease';
-- Make joints, restore original anchor and collision states
for _, Part in pairs(Selection.Items) do
@@ -373,8 +372,7 @@ function HideHandles()
Handles.Parent = nil;
-- Clear unnecessary resources
- Connections.AutofocusHandle:disconnect();
- Connections.AutofocusHandle = nil;
+ ClearConnection 'AutofocusHandle';
end;
diff --git a/tools/Rotate.lua b/tools/Rotate.lua
index 51a320f..12f20cd 100644
--- a/tools/Rotate.lua
+++ b/tools/Rotate.lua
@@ -250,8 +250,7 @@ function AttachHandles(Part, Autofocus)
-- Disable autofocus if not requested and on
elseif not Autofocus and Connections.AutofocusHandle then
- Connections.AutofocusHandle:disconnect();
- Connections.AutofocusHandle = nil;
+ ClearConnection 'AutofocusHandle';
end;
-- Just attach and show the handles if they already exist
@@ -312,8 +311,8 @@ function AttachHandles(Part, Autofocus)
Connections.HandleRelease = UserInputService.InputEnded:connect(function (InputInfo, GameProcessedEvent)
- -- Make sure this was button 1 being released
- if InputInfo.UserInputType ~= Enum.UserInputType.MouseButton1 then
+ -- Make sure this was button 1 being released, and rotating is ongoing
+ if not HandleRotating or (InputInfo.UserInputType ~= Enum.UserInputType.MouseButton1) then
return;
end;
@@ -324,8 +323,7 @@ function AttachHandles(Part, Autofocus)
HandleRotating = false;
-- Clear this connection to prevent it from firing again
- Connections.HandleRelease:disconnect();
- Connections.HandleRelease = nil;
+ ClearConnection 'HandleRelease';
-- Make joints, restore original anchor and collision states
for _, Part in pairs(Selection.Items) do
@@ -390,10 +388,7 @@ function HideHandles()
Handles.Parent = nil;
-- Disable handle autofocus if enabled
- if Connections.AutofocusHandle then
- Connections.AutofocusHandle:disconnect();
- Connections.AutofocusHandle = nil;
- end;
+ ClearConnection 'AutofocusHandle';
end;
From 9a8d94e3609378c88d28ce161972fdfd8ad6a520 Mon Sep 17 00:00:00 2001
From: Robert Chiquini
Date: Sat, 8 Apr 2017 22:43:46 -0700
Subject: [PATCH 03/11] Ensure dragging is desired on part creation in New Part
tool
This change makes sure that dragging is still desired by the
user by the time their new part replicates to their client and
is selected.
Signed-off-by: Robert Chiquini
---
tools/NewPart.lua | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/tools/NewPart.lua b/tools/NewPart.lua
index 6ffa2bb..1bb1bfe 100644
--- a/tools/NewPart.lua
+++ b/tools/NewPart.lua
@@ -121,11 +121,22 @@ function EnableClickCreation()
return;
end;
+ -- Enable new part dragging
+ DragNewParts = true;
+
-- Create the part
CreatePart(NewPartTool.Type);
end);
+ -- Listen for click releases
+ Connections.ClickReleaseListener = Support.AddUserInputListener('Ended', 'MouseButton1', true, function ()
+
+ -- Cancel dragging new parts if mouse button is released
+ DragNewParts = false;
+
+ end);
+
end;
function CreatePart(Type)
@@ -171,7 +182,9 @@ function CreatePart(Type)
Core.EquipTool(MoveTool);
-- Enable dragging to allow easy positioning of the created part
- MoveTool.SetUpDragging(Part);
+ if DragNewParts then
+ MoveTool.SetUpDragging(Part);
+ end;
end;
From 21008bc52b46943a32f0315b8810eca0fe203c8d Mon Sep 17 00:00:00 2001
From: Robert Chiquini
Date: Sat, 8 Apr 2017 23:14:23 -0700
Subject: [PATCH 04/11] Prevent locked parts from being modified by SyncAPI
Signed-off-by: Robert Chiquini
---
SyncAPI.lua | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 127 insertions(+), 4 deletions(-)
diff --git a/SyncAPI.lua b/SyncAPI.lua
index a2c9cc7..21019fd 100644
--- a/SyncAPI.lua
+++ b/SyncAPI.lua
@@ -43,10 +43,8 @@ Actions = {
-- Clones the given parts
-- Make sure the given items are all parts
- for _, Part in pairs(Parts) do
- if not Part:IsA 'BasePart' then
- return;
- end;
+ if not ArePartsSelectable(Parts) then
+ return;
end;
-- Cache up permissions for all private areas
@@ -126,6 +124,11 @@ Actions = {
end;
+ -- Ensure relevant parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -173,6 +176,11 @@ Actions = {
end;
+ -- Ensure relevant parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -209,6 +217,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -269,6 +282,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -331,6 +349,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -391,6 +414,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -433,6 +461,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -472,6 +505,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -527,6 +565,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -597,6 +640,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -652,6 +700,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -725,6 +778,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -772,6 +830,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -834,6 +897,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -890,6 +958,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -953,6 +1026,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -987,6 +1065,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -1021,6 +1104,11 @@ Actions = {
end;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -1055,6 +1143,11 @@ Actions = {
['CreateWelds'] = function (Parts, TargetPart)
-- Creates welds for the given parts to the target part
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -1113,6 +1206,11 @@ Actions = {
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
local WeldsRemoved = 0;
-- Cache up permissions for all private areas
@@ -1168,6 +1266,11 @@ Actions = {
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -1213,6 +1316,11 @@ Actions = {
return;
end;
+ -- Ensure parts are selectable
+ if not ArePartsSelectable(Parts) then
+ return;
+ end;
+
-- Cache up permissions for all private areas
local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Parts), Player);
@@ -1312,6 +1420,21 @@ Actions = {
};
+function ArePartsSelectable(Parts)
+ -- Returns whether the parts are selectable
+
+ -- Check whether each part is selectable
+ for _, Part in pairs(Parts) do
+ if not Part:IsA 'BasePart' or Part.Locked then
+ return false;
+ end;
+ end;
+
+ -- Return true if all parts are selectable
+ return true;
+
+end;
+
-- Provide an interface into the module
return {
From 97e9bc4163cf62adc458c46fbfe29c5e74498921 Mon Sep 17 00:00:00 2001
From: Robert Chiquini
Date: Sat, 8 Apr 2017 23:48:20 -0700
Subject: [PATCH 05/11] Reject clients not operating a tool from calling its
SyncAPI
This change makes the SyncAPI reject requests from clients other
than the one operating the tool, for security reasons.
Signed-off-by: Robert Chiquini
---
SyncAPI.lua | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/SyncAPI.lua b/SyncAPI.lua
index 21019fd..1f785b9 100644
--- a/SyncAPI.lua
+++ b/SyncAPI.lua
@@ -1435,6 +1435,27 @@ function ArePartsSelectable(Parts)
end;
+-- Keep current player updated in tool mode
+if ToolMode == 'Tool' then
+
+ -- Set current player
+ Player = Players:GetPlayerFromCharacter(Tool.Parent);
+
+ -- Stay updated with latest player operating the tool
+ Tool.AncestryChanged:Connect(function (Child, Parent)
+
+ -- Ensure tool's parent changed
+ if Child ~= Tool then
+ return;
+ end;
+
+ -- Update current player
+ Player = Players:GetPlayerFromCharacter(Parent);
+
+ end);
+
+end;
+
-- Provide an interface into the module
return {
@@ -1450,8 +1471,10 @@ return {
return;
end;
- -- Update the Player pointer
- Player = Client;
+ -- Ensure client is current player in tool mode
+ if ToolMode == 'Tool' then
+ assert(Player and (Client == Player), 'Permission denied for client');
+ end;
-- Execute valid actions
return Action(...);
From a0e0d387fdead8a967632a19b8cff0d3c56a00c2 Mon Sep 17 00:00:00 2001
From: Robert Chiquini
Date: Sat, 8 Apr 2017 23:59:23 -0700
Subject: [PATCH 06/11] Prevent rectangle selection while new parts load in New
Part tool
Signed-off-by: Robert Chiquini
---
tools/NewPart.lua | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/NewPart.lua b/tools/NewPart.lua
index 1bb1bfe..98c986b 100644
--- a/tools/NewPart.lua
+++ b/tools/NewPart.lua
@@ -123,6 +123,7 @@ function EnableClickCreation()
-- Enable new part dragging
DragNewParts = true;
+ Core.Targeting.CancelSelecting();
-- Create the part
CreatePart(NewPartTool.Type);
From 93e8fe9974a830aba191b28484a26512f50ad2bd Mon Sep 17 00:00:00 2001
From: Robert Chiquini
Date: Sun, 9 Apr 2017 00:10:17 -0700
Subject: [PATCH 07/11] Round displayed increment field numbers to 4 decimal
places
This change should let allow the user to see more accurately what
they have set for their increment while still preventing floating
point precision issues from being visible.
Signed-off-by: Robert Chiquini
---
tools/Move.lua | 2 +-
tools/Resize.lua | 2 +-
tools/Rotate.lua | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/Move.lua b/tools/Move.lua
index 3f1d6cc..bfc7613 100644
--- a/tools/Move.lua
+++ b/tools/Move.lua
@@ -103,7 +103,7 @@ function ShowUI()
local IncrementInput = MoveTool.UI.IncrementOption.Increment.TextBox;
IncrementInput.FocusLost:connect(function (EnterPressed)
MoveTool.Increment = tonumber(IncrementInput.Text) or MoveTool.Increment;
- IncrementInput.Text = Support.Round(MoveTool.Increment, 3);
+ IncrementInput.Text = Support.Round(MoveTool.Increment, 4);
end);
-- Add functionality to the position inputs
diff --git a/tools/Resize.lua b/tools/Resize.lua
index 14967ab..c01b297 100644
--- a/tools/Resize.lua
+++ b/tools/Resize.lua
@@ -103,7 +103,7 @@ function ShowUI()
local IncrementInput = ResizeTool.UI.IncrementOption.Increment.TextBox;
IncrementInput.FocusLost:connect(function (EnterPressed)
ResizeTool.Increment = tonumber(IncrementInput.Text) or ResizeTool.Increment;
- IncrementInput.Text = Support.Round(ResizeTool.Increment, 3);
+ IncrementInput.Text = Support.Round(ResizeTool.Increment, 4);
end);
-- Add functionality to the size inputs
diff --git a/tools/Rotate.lua b/tools/Rotate.lua
index 12f20cd..5e80de1 100644
--- a/tools/Rotate.lua
+++ b/tools/Rotate.lua
@@ -110,7 +110,7 @@ function ShowUI()
local IncrementInput = RotateTool.UI.IncrementOption.Increment.TextBox;
IncrementInput.FocusLost:connect(function (EnterPressed)
RotateTool.Increment = tonumber(IncrementInput.Text) or RotateTool.Increment;
- IncrementInput.Text = Support.Round(RotateTool.Increment, 3);
+ IncrementInput.Text = Support.Round(RotateTool.Increment, 4);
end);
-- Add functionality to the rotation inputs
From ac5b0256d6d8f3766a10291a468ef285558dc55b Mon Sep 17 00:00:00 2001
From: Robert Chiquini
Date: Sun, 9 Apr 2017 00:56:52 -0700
Subject: [PATCH 08/11] Add T as alias hotkey to R for snapping in Rotate tool
This change restores T as a hotkey for snapped pivot point selection
as an alias for the new R hotkey, which should help not disrupt
the workflows of users accustomed to using the T key.
Signed-off-by: Robert Chiquini
---
tools/Rotate.lua | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/tools/Rotate.lua b/tools/Rotate.lua
index 5e80de1..f58b0e8 100644
--- a/tools/Rotate.lua
+++ b/tools/Rotate.lua
@@ -491,7 +491,11 @@ function BindShortcutKeys()
NudgeSelectionByAxis(Enum.Axis.Y, 1);
-- Start snapping when the R key is pressed down, and it's not the selection clearing hotkey
- elseif InputInfo.KeyCode == Enum.KeyCode.R and not Selection.Multiselecting then
+ elseif (InputInfo.KeyCode == Enum.KeyCode.R) and not Selection.Multiselecting then
+ StartSnapping();
+
+ -- Start snapping when T key is pressed down (alias)
+ elseif InputInfo.KeyCode == Enum.KeyCode.T then
StartSnapping();
end;
From abc03395bd45bc9192c01c4e0ac95ee244fefb8e Mon Sep 17 00:00:00 2001
From: Robert Chiquini
Date: Sun, 9 Apr 2017 00:59:04 -0700
Subject: [PATCH 09/11] Clean up snapping options when
SnapTracking.StopTracking() is called
This should fix an issue where snapping does not work at first try
when using the rotate tool after equipping the move tool (which
sets a target blacklist and expects SnapTracking.StopTracking()
to clean it up regardless of whether tracking is ongoing or not).
Signed-off-by: Robert Chiquini
---
SnapTracking.lua | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/SnapTracking.lua b/SnapTracking.lua
index b79dcfd..c05d3dd 100644
--- a/SnapTracking.lua
+++ b/SnapTracking.lua
@@ -212,6 +212,17 @@ end;
function SnapTracking.StopTracking()
-- Stops tracking the current closest snapping point, cleans up
+ -- Clear the previous tracking target, and callback
+ SnapTracking.Target = nil;
+ SnapTracking.Callback = nil;
+
+ -- Reset snapping point options
+ SnapTracking.TrackFaceCentroids = true;
+ SnapTracking.TrackEdgeMidpoints = true;
+ SnapTracking.TrackCorners = true;
+ SnapTracking.TargetFilter = nil;
+ SnapTracking.TargetBlacklist = {};
+
-- Make sure we're currently tracking
if not SnapTracking.Enabled then
return;
@@ -224,18 +235,6 @@ function SnapTracking.StopTracking()
-- Clear the point marker UI from the screen
SnapTracking.ClearUI();
- -- Clear the previous tracking target, and callback
- SnapTracking.Target = nil;
- SnapTracking.Callback = nil;
-
- -- Reset snapping point options
- SnapTracking.TrackFaceCentroids = true;
- SnapTracking.TrackEdgeMidpoints = true;
- SnapTracking.TrackCorners = true;
-
- SnapTracking.TargetFilter = nil;
- SnapTracking.TargetBlacklist = {};
-
-- Indicate that tracking is no longer enabled
SnapTracking.Enabled = false;
From 740a037b2386e57355c891cc4ed6fd63dbaf6ee1 Mon Sep 17 00:00:00 2001
From: Robert Chiquini
Date: Sun, 9 Apr 2017 06:54:22 -0700
Subject: [PATCH 10/11] Add visual guides for snapping in the Resize tool
Signed-off-by: Robert Chiquini
---
tools/Resize.lua | 151 +++++++++++++++++++++++++++++++++++++----------
1 file changed, 121 insertions(+), 30 deletions(-)
diff --git a/tools/Resize.lua b/tools/Resize.lua
index c01b297..e29bd77 100644
--- a/tools/Resize.lua
+++ b/tools/Resize.lua
@@ -746,10 +746,13 @@ PointSnapped = Core.RbxUtility.CreateSignal();
function StartSnapping()
-- Make sure snapping isn't already enabled
- if SnapTracking.Enabled then
+ if SnappingStage or SnapTracking.Enabled then
return;
end;
+ -- Start first snapping stage
+ SnappingStage = 'Starting';
+
-- Only enable corner snapping
SnapTracking.TrackEdgeMidpoints = false;
SnapTracking.TrackFaceCentroids = false;
@@ -775,48 +778,89 @@ function StartSnapping()
SnappingStartSelectionState = PreparePartsForResizing();
AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Selection.Items), Core.Player);
+ -- Pause snapping
+ SnapTracking.StopTracking();
+
+ -- Start a direction line
+ DirectionLine = Core.Tool.Interfaces.SnapLine:Clone();
+ DirectionLine.Parent = Core.UI;
+ DirectionLine.Visible = false;
+
-- Track changes for history
TrackChange();
-- Listen for when the user drags
- Connections.SnapDrag = Support.AddUserInputListener('Changed', 'MouseMovement', false, function (Input)
+ Connections.SnapDrag = Support.AddUserInputListener('Changed', 'MouseMovement', true, function (Input)
-- Update the latest aim
SnappingEndAim = Vector2.new(Input.Position.X, Input.Position.Y);
+ ScreenSnappedPoint = Workspace.CurrentCamera:WorldToScreenPoint(SnappingStartPoint);
+ ScreenSnappedPoint = Vector2.new(ScreenSnappedPoint.X, ScreenSnappedPoint.Y);
- -- Use the mouse position to figure out the resize direction (until after 20px)
- if SnappingStage == 'Direction' then
+ -- Calculate direction setting length
+ local DirectionSettingLength = math.min(50, math.max(50, (SnappingStartAim - ScreenSnappedPoint).magnitude * 1.5));
- -- Check the length
- local Length = (SnappingEndAim - SnappingStartAim).magnitude;
- if Length < 20 then
- return;
- end;
+ -- Use the mouse position to figure out the resize direction (until after direction setting length)
+ if SnappingStage == 'Direction' then
- local DragSlope = (SnappingEndAim.Y - SnappingStartAim.Y) / (SnappingEndAim.X - SnappingStartAim.X);
+ -- Get current angle from snap point
+ local DragAngle = math.deg(math.atan2(SnappingEndAim.Y - ScreenSnappedPoint.Y, SnappingEndAim.X - ScreenSnappedPoint.X));
+ DragAngle = (DragAngle > 0) and (DragAngle - 360) or DragAngle;
-- Go through corner offsets representing the possible directions
local Directions = {};
for _, Direction in pairs(SnappingStartDirections) do
-- Map the corner & corner offset to screen points
- local ScreenSnappedPoint = Workspace.CurrentCamera:WorldToScreenPoint(SnappingStartPoint);
local ScreenOffsetPoint = Workspace.CurrentCamera:WorldToScreenPoint(Direction.Offset);
- -- Get the slope representing the direction (based on the mapped screen points)
- local DirectionSlope = (ScreenOffsetPoint.Y - ScreenSnappedPoint.Y) / (ScreenOffsetPoint.X - ScreenSnappedPoint.X);
+ -- Get direction angle from snap point
+ local DirectionAngle = math.deg(math.atan2(ScreenOffsetPoint.Y - ScreenSnappedPoint.Y, ScreenOffsetPoint.X - ScreenSnappedPoint.X));
+ DirectionAngle = (DirectionAngle > 0) and (DirectionAngle - 360) or DirectionAngle;
+
+ -- Calculate delta between drag and direction angles
+ local AngleDelta = math.abs(DragAngle - DirectionAngle) % 180;
+ AngleDelta = (AngleDelta > 90) and (180 - AngleDelta) or AngleDelta;
- -- Calculate the similarity between the drag & direction slopes
- local SlopeDelta = math.abs(math.abs(DragSlope) - math.abs(DirectionSlope));
- table.insert(Directions, { Face = Direction.Face, SlopeDelta = SlopeDelta, Offset = Direction.Offset });
+ -- Insert the potential direction
+ table.insert(Directions, {
+ Face = Direction.Face,
+ AngleDelta = AngleDelta,
+ DirectionAngle = DirectionAngle,
+ Offset = Direction.Offset
+ });
end;
- -- Get the direction slope closest to the mouse's
+ -- Get the direction most similar to the dragging angle
table.sort(Directions, function (A, B)
- return A.SlopeDelta < B.SlopeDelta;
+ return A.AngleDelta < B.AngleDelta;
end);
+ -- Center direction line at snap point
+ DirectionLine.Position = UDim2.new(0, ScreenSnappedPoint.X, 0, ScreenSnappedPoint.Y);
+
+ -- Orient direction line towards drag direction
+ if math.abs(DragAngle - Directions[1].DirectionAngle) <= 90 then
+ DirectionLine.Rotation = Directions[1].DirectionAngle;
+ else
+ DirectionLine.Rotation = 180 + Directions[1].DirectionAngle;
+ end;
+
+ -- Show the direction line
+ DirectionLine.PointMarker.Rotation = -DirectionLine.Rotation;
+ DirectionLine.SnapProgress.Size = UDim2.new(0, DirectionSettingLength, 2, 0);
+ DirectionLine.Visible = true;
+
+ -- Check if drag has passed direction setting length
+ local Length = (SnappingEndAim - ScreenSnappedPoint).magnitude;
+ if Length < DirectionSettingLength then
+ return;
+ end;
+
+ -- Clear the direction line
+ DirectionLine:Destroy()
+
-- Select the resizing direction that was closest to the mouse drag
SnappingDirection = Directions[1].Face;
SnappingDirectionOffset = Directions[1].Offset;
@@ -824,11 +868,24 @@ function StartSnapping()
-- Move to the destination-picking stage of snapping
SnappingStage = 'Destination';
+ -- Set destination-stage snapping options
+ SnapTracking.TrackEdgeMidpoints = true;
+ SnapTracking.TrackFaceCentroids = true;
SnapTracking.TargetFilter = function (Target) return not Target.Locked; end;
SnapTracking.TargetBlacklist = Selection.Items;
- -- Resize in the selected direction up to the targeted destination
- elseif SnappingStage == 'Destination' then
+ -- Re-enable snapping to select destination
+ SnapTracking.StartTracking(function (NewPoint)
+ if NewPoint and NewPoint.p ~= SnappedPoint then
+ SnappedPoint = NewPoint.p;
+ PointSnapped:fire(NewPoint.p);
+ end;
+ end);
+
+ -- Start a distance alignment line
+ AlignmentLine = Core.Tool.Interfaces.SnapLineSegment:Clone();
+ AlignmentLine.Visible = false;
+ AlignmentLine.Parent = Core.UI;
end;
@@ -837,7 +894,10 @@ function StartSnapping()
-- Listen for when a new point is snapped
Connections.Snap = PointSnapped:connect(function (SnappedPoint)
+ -- Resize to snap point if in the destination stage of snapping
if SnappingStage == 'Destination' then
+
+ -- Calculate direction and distance to resize towards
local Direction = (SnappingDirectionOffset - SnappingStartPoint).unit;
local Distance = (SnappedPoint - SnappingStartPoint):Dot(Direction);
@@ -857,24 +917,41 @@ function StartSnapping()
end;
end;
+ -- Get snap point and destination point screen positions for UI alignment
+ local ScreenStartPoint = Workspace.CurrentCamera:WorldToScreenPoint(SnappingStartPoint + (Direction * Distance));
+ ScreenStartPoint = Vector2.new(ScreenStartPoint.X, ScreenStartPoint.Y);
+ local ScreenDestinationPoint = Workspace.CurrentCamera:WorldToScreenPoint(SnappedPoint);
+ ScreenDestinationPoint = Vector2.new(ScreenDestinationPoint.X, ScreenDestinationPoint.Y)
+
+ -- Update the distance alignment line
+ local AlignmentAngle = math.deg(math.atan2(ScreenDestinationPoint.Y - ScreenStartPoint.Y, ScreenDestinationPoint.X - ScreenStartPoint.X));
+ local AlignmentCenter = ScreenStartPoint:Lerp(ScreenDestinationPoint, 0.5);
+ AlignmentLine.Position = UDim2.new(0, AlignmentCenter.X, 0, AlignmentCenter.Y);
+ AlignmentLine.Rotation = AlignmentAngle;
+ AlignmentLine.Size = UDim2.new(0, (ScreenDestinationPoint - ScreenStartPoint).magnitude, 0, 1);
+ AlignmentLine.PointMarkerA.Rotation = -AlignmentAngle;
+ AlignmentLine.Visible = true;
+
end;
end);
- -- Listen for the end of the snapping
- Connections.SnapDragEnd = Support.AddUserInputListener('Ended', 'MouseButton1', false, function (Input)
+ end);
+
+ -- Listen for the end of the snapping
+ Connections.SnapDragEnd = Support.AddUserInputListener('Ended', 'MouseButton1', true, function (Input)
- -- Restore the selection's original state
+ -- If destination stage was reached, restore the selection's original state
+ if SnappingStage == 'Destination' then
for Part, PartState in pairs(SnappingStartSelectionState) do
Part:MakeJoints();
Part.CanCollide = PartState.CanCollide;
Part.Anchored = PartState.Anchored;
end;
+ end;
- -- Finish snapping
- FinishSnapping();
-
- end);
+ -- Finish snapping
+ FinishSnapping();
end);
@@ -882,14 +959,27 @@ end;
function FinishSnapping()
- -- Make sure snapping is enabled
- if not SnapTracking.Enabled then
+ -- Ensure snapping is ongoing
+ if not SnappingStage then
return;
end;
+ -- Disable any snapping stage
+ SnappingStage = nil;
+
-- Stop snap point tracking
SnapTracking.StopTracking();
+ -- Clear any UI
+ if DirectionLine then
+ DirectionLine:Destroy();
+ DirectionLine = nil;
+ end;
+ if AlignmentLine then
+ AlignmentLine:Destroy();
+ AlignmentLine = nil;
+ end;
+
-- Register any change
if HistoryRecord then
RegisterChange();
@@ -914,7 +1004,8 @@ function GetFaceOffsetsFromCorner(Part, Point)
for _, Face in pairs(Faces) do
-- Calculate the offset from the corner in the direction of the face
- local Offset = CFrame.new(Point) * CFrame.Angles(Part.CFrame:toEulerAnglesXYZ()) * Vector3.FromNormalId(Face);
+ local FaceOffset = (Vector3.FromNormalId(Face) * Part.Size) / 2;
+ local Offset = CFrame.new(Point) * CFrame.Angles(Part.CFrame:toEulerAnglesXYZ()) * FaceOffset;
table.insert(Offsets, { Face = Face, Offset = Offset });
end;
From 055e86de7ad8a0d67351ef3c6ef17a99b18bf518 Mon Sep 17 00:00:00 2001
From: Robert Chiquini
Date: Sun, 9 Apr 2017 07:17:15 -0700
Subject: [PATCH 11/11] Update asset builds to 2.0.2
Signed-off-by: Robert Chiquini
---
build/Building Tools by F3X (plugin).rbxmx | 4017 +++++++++-------
build/Building Tools by F3X.rbxmx | 5061 +++++++++++---------
2 files changed, 5224 insertions(+), 3854 deletions(-)
diff --git a/build/Building Tools by F3X (plugin).rbxmx b/build/Building Tools by F3X (plugin).rbxmx
index f1f478e..6d5142c 100644
--- a/build/Building Tools by F3X (plugin).rbxmx
+++ b/build/Building Tools by F3X (plugin).rbxmx
@@ -1,11 +1,11 @@
null
nil
- -
+
-
Building Tools by F3X
-
-
+
-
false
-0.5
@@ -76,7 +76,7 @@
0.800000012
-
-
+
-
4294967295
5
@@ -85,7 +85,7 @@
0
- -
+
-
4294967295
2
@@ -94,7 +94,7 @@
0
- -
+
-
4294967295
3
@@ -103,7 +103,7 @@
0
- -
+
-
4294967295
0
@@ -112,7 +112,7 @@
0
- -
+
-
4294967295
1
@@ -121,7 +121,7 @@
0
- -
+
-
4294967295
4
@@ -131,17 +131,17 @@
- -
+
-
Version
- 2.0.1
+ 2.0.2
- -
+
-
SupportLibrary
- {AF627CE6-3567-4B19-9CF5-F9C8CC50C418}
+ {276F344C-469D-449C-A433-FBB18E3B8592}
- -
+
-
SecurityModule
- {76D5254D-1B8B-4F38-BB29-0EC26AF3AA53}
+ {4E96BCE7-DB08-47A6-A42B-4833931B2534}
- -
+
-
Region by AxisAngle
- {BEC01F60-B2C1-4440-9F13-256054C7BCB5}
+ {89D34A64-F5F0-4495-B701-DFE9DF5DF47F}
- -
+
-
false
@@ -1818,11 +1818,11 @@ end;
-- Expose GetLibraries function
_G.GetLibraries = GetLibraries;]]>
-
-
+
-
F3X/SupportLibrary@1.0.0
- {1BFC3C3C-D06F-4B5C-B79D-70FF6735DB05}
+ {3828CCBC-611C-4CF0-B73C-54AAC681E6BF}
-
-
+
-
Metadata
- {BF155B56-AE7D-4141-95CC-6A0406FB470B}
+ {AC4DF028-750A-4E46-8C20-211ABC74B847}
- -
+
-
F3X/Cheer@0.0.1
- {98A4ED7A-8D23-4CC2-B199-CBDFD6FF8F8E}
+ {16EFB4A5-2040-4B3A-80D3-241B3559EDD2}
-
-
+
-
SupportLibrary
- {0B356333-F133-4A5C-A3DB-ADE5E8F1CB44}
+ {F44136EB-B2E1-421E-9BD5-0D84C8A96319}
- -
+
-
Metadata
- {07F16FB1-2B62-4ACA-B1FF-DE8D5DBF710C}
+ {6D285C58-D789-4B70-9DC4-5C0A69C25364}
- -
+
-
F3X/Try@1.0.0
- {1BBDA9BF-F632-4F2D-8989-662255D82D8E}
+ {7803A1CF-A0BD-44FB-8D3C-6197C12C636A}
-
-
+
-
SupportLibrary
@@ -5232,11 +5232,11 @@ end;
return SupportLibrary;]]>
- -
+
-
Metadata
- {52186982-44A5-4662-942E-26B8CCED7DA6}
+ {E3EA7C7A-3B45-486A-BDA8-BC9544AB6DD6}
- -
+
-
SerializationModule
- {D163F155-7BCD-4459-B9C8-5BB9ACFEECBD}
+ {1ECE6BA9-B787-4C56-A8E8-628058296208}
- -
+
-
SyncAPI
-
-
+
-
SyncModule
- {49365CC0-6516-4C49-9260-E2110558F236}
+ {EC0655C1-19C5-46D5-80C5-022FCDCEA683}
- -
+
-
ServerEndpoint
-
-
+
-
false
ServerEndpointScript
- {4B29E480-CBE5-4E88-A026-FCAAD6F2E57D}
+ {F6CFC9BD-5C68-4659-9451-4B5E8FAB5C2C}
- -
+
-
false
@@ -7103,22 +7249,22 @@ end;]]>
- -
+
-
Loaded
false
-
-
+
-
ComponentCount
0
-
-
+
-
false
ComponentCounter
- {A6B5CC4F-EB25-4EEF-8CD5-9E2608E6B9D2}
+ {EDDC90CF-4D08-424E-A71E-DB82F6D5733E}
- -
+
-
false
@@ -7156,11 +7302,11 @@ Indicator.Value = true;]]>
- -
+
-
Assets
-
+ {FA84AA5E-2C4A-4101-A9CA-8C71F770285B}
return Assets;]]>
- -
+
-
Core
- {958EE6C4-B502-4727-8B0E-C16FDB0960C0}
+ {6B760565-60C5-48B3-A318-D45F5FC82581}
- -
+
-
false
@@ -7865,15 +8048,15 @@ local Core = require(Tool:WaitForChild 'Core');
require(Tool.Tools.CoreToolLoader);]]>
- -
+
-
Tools
-
-
+
-
MoveTool
- {BA9280AF-0194-4E51-BBFC-54865E1DDBF6}
+ {80377989-C9D8-4BF7-9CA7-D00D66BD7980}
- -
+
-
ResizeTool
- {F0B36D21-330E-4356-BA8F-EFE7B3932638}
+ {EF60C14F-E6FD-43A5-8D4C-45E623CB66C0}
0) and (DragAngle - 360) or DragAngle;
-- Go through corner offsets representing the possible directions
local Directions = {};
for _, Direction in pairs(SnappingStartDirections) do
-- Map the corner & corner offset to screen points
- local ScreenSnappedPoint = Workspace.CurrentCamera:WorldToScreenPoint(SnappingStartPoint);
local ScreenOffsetPoint = Workspace.CurrentCamera:WorldToScreenPoint(Direction.Offset);
- -- Get the slope representing the direction (based on the mapped screen points)
- local DirectionSlope = (ScreenOffsetPoint.Y - ScreenSnappedPoint.Y) / (ScreenOffsetPoint.X - ScreenSnappedPoint.X);
+ -- Get direction angle from snap point
+ local DirectionAngle = math.deg(math.atan2(ScreenOffsetPoint.Y - ScreenSnappedPoint.Y, ScreenOffsetPoint.X - ScreenSnappedPoint.X));
+ DirectionAngle = (DirectionAngle > 0) and (DirectionAngle - 360) or DirectionAngle;
- -- Calculate the similarity between the drag & direction slopes
- local SlopeDelta = math.abs(math.abs(DragSlope) - math.abs(DirectionSlope));
- table.insert(Directions, { Face = Direction.Face, SlopeDelta = SlopeDelta, Offset = Direction.Offset });
+ -- Calculate delta between drag and direction angles
+ local AngleDelta = math.abs(DragAngle - DirectionAngle) % 180;
+ AngleDelta = (AngleDelta > 90) and (180 - AngleDelta) or AngleDelta;
+
+ -- Insert the potential direction
+ table.insert(Directions, {
+ Face = Direction.Face,
+ AngleDelta = AngleDelta,
+ DirectionAngle = DirectionAngle,
+ Offset = Direction.Offset
+ });
end;
- -- Get the direction slope closest to the mouse's
+ -- Get the direction most similar to the dragging angle
table.sort(Directions, function (A, B)
- return A.SlopeDelta < B.SlopeDelta;
+ return A.AngleDelta < B.AngleDelta;
end);
+ -- Center direction line at snap point
+ DirectionLine.Position = UDim2.new(0, ScreenSnappedPoint.X, 0, ScreenSnappedPoint.Y);
+
+ -- Orient direction line towards drag direction
+ if math.abs(DragAngle - Directions[1].DirectionAngle) <= 90 then
+ DirectionLine.Rotation = Directions[1].DirectionAngle;
+ else
+ DirectionLine.Rotation = 180 + Directions[1].DirectionAngle;
+ end;
+
+ -- Show the direction line
+ DirectionLine.PointMarker.Rotation = -DirectionLine.Rotation;
+ DirectionLine.SnapProgress.Size = UDim2.new(0, DirectionSettingLength, 2, 0);
+ DirectionLine.Visible = true;
+
+ -- Check if drag has passed direction setting length
+ local Length = (SnappingEndAim - ScreenSnappedPoint).magnitude;
+ if Length < DirectionSettingLength then
+ return;
+ end;
+
+ -- Clear the direction line
+ DirectionLine:Destroy()
+
-- Select the resizing direction that was closest to the mouse drag
SnappingDirection = Directions[1].Face;
SnappingDirectionOffset = Directions[1].Offset;
@@ -9796,11 +10021,24 @@ function StartSnapping()
-- Move to the destination-picking stage of snapping
SnappingStage = 'Destination';
+ -- Set destination-stage snapping options
+ SnapTracking.TrackEdgeMidpoints = true;
+ SnapTracking.TrackFaceCentroids = true;
SnapTracking.TargetFilter = function (Target) return not Target.Locked; end;
SnapTracking.TargetBlacklist = Selection.Items;
- -- Resize in the selected direction up to the targeted destination
- elseif SnappingStage == 'Destination' then
+ -- Re-enable snapping to select destination
+ SnapTracking.StartTracking(function (NewPoint)
+ if NewPoint and NewPoint.p ~= SnappedPoint then
+ SnappedPoint = NewPoint.p;
+ PointSnapped:fire(NewPoint.p);
+ end;
+ end);
+
+ -- Start a distance alignment line
+ AlignmentLine = Core.Tool.Interfaces.SnapLineSegment:Clone();
+ AlignmentLine.Visible = false;
+ AlignmentLine.Parent = Core.UI;
end;
@@ -9809,7 +10047,10 @@ function StartSnapping()
-- Listen for when a new point is snapped
Connections.Snap = PointSnapped:connect(function (SnappedPoint)
+ -- Resize to snap point if in the destination stage of snapping
if SnappingStage == 'Destination' then
+
+ -- Calculate direction and distance to resize towards
local Direction = (SnappingDirectionOffset - SnappingStartPoint).unit;
local Distance = (SnappedPoint - SnappingStartPoint):Dot(Direction);
@@ -9829,24 +10070,39 @@ function StartSnapping()
end;
end;
+ -- Update the distance alignment line
+ local ScreenStartPoint = Workspace.CurrentCamera:WorldToScreenPoint(SnappingStartPoint + (Direction * Distance));
+ ScreenStartPoint = Vector2.new(ScreenStartPoint.X, ScreenStartPoint.Y);
+ local ScreenDestinationPoint = Workspace.CurrentCamera:WorldToScreenPoint(SnappedPoint);
+ ScreenDestinationPoint = Vector2.new(ScreenDestinationPoint.X, ScreenDestinationPoint.Y)
+ local AlignmentAngle = math.deg(math.atan2(ScreenDestinationPoint.Y - ScreenStartPoint.Y, ScreenDestinationPoint.X - ScreenStartPoint.X));
+ local AlignmentCenter = ScreenStartPoint:Lerp(ScreenDestinationPoint, 0.5);
+ AlignmentLine.Position = UDim2.new(0, AlignmentCenter.X, 0, AlignmentCenter.Y);
+ AlignmentLine.Rotation = AlignmentAngle;
+ AlignmentLine.Size = UDim2.new(0, (ScreenDestinationPoint - ScreenStartPoint).magnitude, 0, 1);
+ AlignmentLine.PointMarkerA.Rotation = -AlignmentAngle;
+ AlignmentLine.Visible = true;
+
end;
end);
- -- Listen for the end of the snapping
- Connections.SnapDragEnd = Support.AddUserInputListener('Ended', 'MouseButton1', false, function (Input)
+ end);
- -- Restore the selection's original state
+ -- Listen for the end of the snapping
+ Connections.SnapDragEnd = Support.AddUserInputListener('Ended', 'MouseButton1', true, function (Input)
+
+ -- If destination stage was reached, restore the selection's original state
+ if SnappingStage == 'Destination' then
for Part, PartState in pairs(SnappingStartSelectionState) do
Part:MakeJoints();
Part.CanCollide = PartState.CanCollide;
Part.Anchored = PartState.Anchored;
end;
+ end;
- -- Finish snapping
- FinishSnapping();
-
- end);
+ -- Finish snapping
+ FinishSnapping();
end);
@@ -9854,14 +10110,27 @@ end;
function FinishSnapping()
- -- Make sure snapping is enabled
- if not SnapTracking.Enabled then
+ -- Ensure snapping is ongoing
+ if not SnappingStage then
return;
end;
+ -- Disable any snapping stage
+ SnappingStage = nil;
+
-- Stop snap point tracking
SnapTracking.StopTracking();
+ -- Clear any UI
+ if DirectionLine then
+ DirectionLine:Destroy();
+ DirectionLine = nil;
+ end;
+ if AlignmentLine then
+ AlignmentLine:Destroy();
+ AlignmentLine = nil;
+ end;
+
-- Register any change
if HistoryRecord then
RegisterChange();
@@ -9886,7 +10155,8 @@ function GetFaceOffsetsFromCorner(Part, Point)
for _, Face in pairs(Faces) do
-- Calculate the offset from the corner in the direction of the face
- local Offset = CFrame.new(Point) * CFrame.Angles(Part.CFrame:toEulerAnglesXYZ()) * Vector3.FromNormalId(Face);
+ local FaceOffset = (Vector3.FromNormalId(Face) * Part.Size) / 2;
+ local Offset = CFrame.new(Point) * CFrame.Angles(Part.CFrame:toEulerAnglesXYZ()) * FaceOffset;
table.insert(Offsets, { Face = Face, Offset = Offset });
end;
@@ -9924,11 +10194,11 @@ end;
return ResizeTool;]]>
- -
+
-
RotateTool
- {B983F910-4440-431B-A881-AB6B5FB4C766}
+ {A7AB7D91-49BD-444B-A952-74ED46D19074}
- -
+
-
PaintTool
- {8323345E-2D2F-4929-A57E-49A834D16BC3}
+ {0EA1E586-EFB4-4214-B3B7-FBC01CDED54C}
-
-
+
-
Colors
- {9E8DF8AA-CC39-498D-BF13-FB3AE5100F5C}
+ {C6EABBA4-1EA9-4305-B756-B8D9A8DF182C}
- -
+
-
MaterialTool
- {4A849024-D15B-435A-AE42-44C636732F6F}
+ {6A8679E1-D40E-457E-9D79-E984DAA8CA4B}
- -
+
-
SurfaceTool
- {FD107264-0289-40DE-B5E3-D7EFCB3BF7DE}
+ {706E28B3-CB18-4AE7-AFDA-9CC3D16B6BD6}
- -
+
-
AnchorTool
- {39BB8B98-872F-45F2-9F81-9938C2770B07}
+ {BE379B00-A4F5-419C-A212-DF9B5314B2C9}
- -
+
-
WeldTool
- {D5D58A5D-A5AE-4B70-8DB9-0F8B3D6B4A00}
+ {ECBCA2B4-1E19-4F4E-83B6-669C1081F4A1}
- -
+
-
TextureTool
- {2008ECA0-2452-425A-B69F-E1D08E5D7849}
+ {EAA36324-C317-42BF-9A80-969E28F10BE8}
- -
+
-
MeshTool
- {17186AB6-E03A-4606-8427-577D2EDCC376}
+ {3B00474D-3D83-4FB0-A224-076485D183D1}
- -
+
-
NewPartTool
- {CE305198-CA4A-41C8-AD59-C58037734E7D}
+ {7E9DE192-2A40-4C2F-B9A5-E817A45736BE}
- -
+
-
CollisionTool
- {4033ADF8-239A-4F3E-9A9E-18DA37C56500}
+ {83B427DA-EA7D-4BAF-908B-40AA669E5579}
- -
+
-
LightingTool
- {D43C35D7-DA24-4CFB-87FF-A6470FD5E1D9}
+ {79DBCE5A-9F71-45B2-A6EA-288D265B4E32}
- -
+
-
DecorateTool
- {D7840BB9-C484-4B12-A9EC-78CC6505EF79}
+ {0E0B695C-8E66-4E0B-90B9-376FCDA2F2A5}
- -
+
-
CoreToolLoader
- {3F5C1C64-696A-4DD0-89F3-DBDED924332B}
+ {4C9EDCE1-0C3D-4DE1-8B26-64D37BA31A4B}
- -
+
-
HistoryModule
- {6288DC45-6776-438D-87AA-228EECDAB939}
+ {4A65DBBA-9B53-4359-9564-49FF0A1627C6}
- -
+
-
SelectionModule
- {70A36175-8C37-4C3D-9EDA-1450A97973E6}
+ {A29F8FD0-608F-47BE-9EFB-44606ADDBD18}
- -
+
-
SnappingModule
- {9BA2249E-0910-42E8-A33B-A7770A0C2C2F}
+ {C34FDBD9-582C-4ACB-BB31-6068DC4E3F11}
- -
+
-
FilterMode
false
-
-
+
-
false
FilterModeEnabler
- {C561BA6D-45E6-4047-B075-C46E5D92043C}
+ {40F29F65-F981-4A7D-A3FB-B378FC62989E}
script.Parent.Value = Workspace.FilteringEnabled;
- -
+
-
BoundingBoxModule
- {06F07FFE-D7C3-4494-BAB7-1FAAA5F5E2C6}
+ {4C69E677-F657-40FA-B390-DEEC5CDD71C6}
- -
+
-
TargetingModule
- {497E9CBE-EE0F-4770-A034-181C9F0B84E5}
+ {5949CB4F-7ECD-4B96-8669-DE93F1807D76}
- -
+
-
Interfaces
-
-
+
-
true
@@ -17053,7 +17369,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -17092,7 +17408,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -17132,7 +17448,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -17183,7 +17499,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -17235,7 +17551,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -17274,7 +17590,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -17325,7 +17641,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -17364,7 +17680,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -17404,7 +17720,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -17459,7 +17775,7 @@ return TargetingModule;]]>
2
- -
+
-
false
@@ -17520,7 +17836,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -17572,7 +17888,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -17611,7 +17927,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -17651,7 +17967,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -17706,7 +18022,7 @@ return TargetingModule;]]>
2
- -
+
-
false
@@ -17767,7 +18083,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -17820,7 +18136,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -17859,7 +18175,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -17899,7 +18215,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -17952,7 +18268,7 @@ return TargetingModule;]]>
- -
+
-
true
@@ -17991,7 +18307,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -18030,7 +18346,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -18070,7 +18386,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -18121,7 +18437,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -18173,7 +18489,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -18212,7 +18528,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -18263,7 +18579,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -18302,7 +18618,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -18342,7 +18658,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -18397,7 +18713,7 @@ return TargetingModule;]]>
2
- -
+
-
false
@@ -18458,7 +18774,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -18510,7 +18826,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -18549,7 +18865,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -18589,7 +18905,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -18644,7 +18960,7 @@ return TargetingModule;]]>
2
- -
+
-
false
@@ -18705,7 +19021,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -18758,7 +19074,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -18797,7 +19113,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -18837,7 +19153,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -18890,7 +19206,7 @@ return TargetingModule;]]>
- -
+
-
true
@@ -18929,7 +19245,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -18969,7 +19285,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -19008,7 +19324,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -19048,7 +19364,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -19099,7 +19415,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -19151,7 +19467,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -19190,7 +19506,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -19241,7 +19557,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -19306,7 +19622,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -19346,7 +19662,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -19401,7 +19717,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -19456,7 +19772,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -19496,7 +19812,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -19535,7 +19851,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -19574,7 +19890,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -19625,7 +19941,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -19664,7 +19980,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -19725,7 +20041,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -19765,7 +20081,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -19821,7 +20137,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -19860,7 +20176,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -19911,7 +20227,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -19950,7 +20266,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -20011,7 +20327,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -20051,7 +20367,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -20107,7 +20423,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -20146,7 +20462,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -20197,7 +20513,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -20236,7 +20552,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -20297,7 +20613,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -20337,7 +20653,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -20393,7 +20709,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -20432,7 +20748,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
true
@@ -20496,7 +20812,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -20537,7 +20853,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -20588,7 +20904,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -20627,7 +20943,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -20667,7 +20983,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -20722,7 +21038,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -20773,7 +21089,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -20812,7 +21128,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -20863,7 +21179,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -20928,7 +21244,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -20968,7 +21284,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -21023,7 +21339,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -21078,7 +21394,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -21118,7 +21434,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -21157,7 +21473,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -21196,7 +21512,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -21247,7 +21563,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -21286,7 +21602,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -21347,7 +21663,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -21387,7 +21703,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -21443,7 +21759,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -21482,7 +21798,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -21533,7 +21849,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -21572,7 +21888,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -21633,7 +21949,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -21673,7 +21989,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -21729,7 +22045,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -21768,7 +22084,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
true
@@ -21832,7 +22148,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -21873,7 +22189,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -21924,7 +22240,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -21963,7 +22279,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -22003,7 +22319,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -22056,7 +22372,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -22095,7 +22411,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
true
@@ -22159,7 +22475,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -22200,7 +22516,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -22251,7 +22567,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -22290,7 +22606,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -22330,7 +22646,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -22385,7 +22701,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -22424,7 +22740,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -22475,7 +22791,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -22540,7 +22856,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -22580,7 +22896,7 @@ return TargetingModule;]]>
1
- -
+
-
true
@@ -22635,7 +22951,7 @@ return TargetingModule;]]>
2
- -
+
-
true
@@ -22690,7 +23006,7 @@ return TargetingModule;]]>
2
- -
+
-
false
@@ -22730,7 +23046,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -22769,7 +23085,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -22808,7 +23124,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
true
@@ -22872,7 +23188,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -22913,7 +23229,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -22964,7 +23280,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -23003,7 +23319,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -23043,7 +23359,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -23099,7 +23415,7 @@ return TargetingModule;]]>
- -
+
-
true
@@ -23138,7 +23454,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -23177,7 +23493,7 @@ return TargetingModule;]]>
false
1
-
-
+
-
false
@@ -23216,7 +23532,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
true
@@ -23280,7 +23596,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -23319,7 +23635,7 @@ return TargetingModule;]]>
false
2
-
-
+
-
false
@@ -23359,7 +23675,7 @@ return TargetingModule;]]>
2
- -
+
-
false
@@ -23412,7 +23728,7 @@ return TargetingModule;]]>
- -
+
-
true
@@ -23476,7 +23792,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -23515,7 +23831,7 @@ return TargetingModule;]]>
false
2
-
-
+
-
false
@@ -23555,7 +23871,7 @@ return TargetingModule;]]>
2
- -
+
-
false
@@ -23608,7 +23924,7 @@ return TargetingModule;]]>
- -
+
-
true
@@ -23672,7 +23988,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -23711,7 +24027,7 @@ return TargetingModule;]]>
false
3
-
-
+
-
false
@@ -23751,7 +24067,7 @@ return TargetingModule;]]>
3
- -
+
-
false
@@ -23804,7 +24120,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -23843,7 +24159,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -23882,7 +24198,7 @@ return TargetingModule;]]>
false
2
-
-
+
-
false
@@ -23922,7 +24238,7 @@ return TargetingModule;]]>
2
- -
+
-
false
@@ -23975,7 +24291,7 @@ return TargetingModule;]]>
- -
+
-
true
@@ -24030,7 +24346,7 @@ return TargetingModule;]]>
2
- -
+
-
true
@@ -24086,7 +24402,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -24140,7 +24456,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -24191,7 +24507,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -24230,7 +24546,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
true
@@ -24285,7 +24601,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -24325,7 +24641,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -24378,7 +24694,7 @@ return TargetingModule;]]>
- -
+
-
true
@@ -24417,7 +24733,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
true
@@ -24481,7 +24797,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -24543,7 +24859,7 @@ return TargetingModule;]]>
- -
+
-
true
@@ -24607,7 +24923,7 @@ return TargetingModule;]]>
true
2
-
-
+
-
false
@@ -24647,7 +24963,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -24709,7 +25025,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -24748,7 +25064,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -24799,7 +25115,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -24838,7 +25154,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -24879,7 +25195,7 @@ return TargetingModule;]]>
- -
+
-
true
@@ -24932,7 +25248,7 @@ return TargetingModule;]]>
true
2
-
-
+
-
false
@@ -24995,7 +25311,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -25034,7 +25350,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -25085,7 +25401,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -25124,7 +25440,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -25165,7 +25481,7 @@ return TargetingModule;]]>
- -
+
-
true
@@ -25218,7 +25534,7 @@ return TargetingModule;]]>
true
2
-
-
+
-
false
@@ -25281,7 +25597,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -25320,7 +25636,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -25371,7 +25687,7 @@ return TargetingModule;]]>
1
- -
+
-
false
@@ -25410,7 +25726,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -25451,7 +25767,7 @@ return TargetingModule;]]>
- -
+
-
true
@@ -25504,7 +25820,7 @@ return TargetingModule;]]>
true
2
-
-
+
-
false
@@ -25567,7 +25883,7 @@ return TargetingModule;]]>
- -
+
-
false
@@ -25606,7 +25922,7 @@ return TargetingModule;]]>
true
1
-
-
+
-
false
@@ -25647,7 +25963,7 @@ return TargetingModule;]]>
- -
+
-
true
@@ -25701,7 +26017,7 @@ return TargetingModule;]]>
true
2
-
-
+
-
false
@@ -25742,7 +26058,7 @@ return TargetingModule;]]>
- -
+
-
true
@@ -25796,7 +26112,7 @@ return TargetingModule;]]>
true
2
-
-
+
-
false
@@ -25837,7 +26153,7 @@ return TargetingModule;]]>
- -
+
-
[Component]
@@ -25965,7 +26281,7 @@ return Component;]]>
- -
+
-
true
@@ -26004,7 +26320,7 @@ return Component;]]>
true
1
-
-
+
-
false
@@ -26043,7 +26359,7 @@ return Component;]]>
true
1
-
-
+
-
false
@@ -26083,7 +26399,7 @@ return Component;]]>
1
- -
+
-
true
@@ -26138,7 +26454,7 @@ return Component;]]>
1
- -
+
-
true
@@ -26193,7 +26509,7 @@ return Component;]]>
1
- -
+
-
false
@@ -26233,7 +26549,7 @@ return Component;]]>
1
- -
+
-
true
@@ -26298,7 +26614,7 @@ return Component;]]>
1
- -
+
-
false
@@ -26349,7 +26665,7 @@ return Component;]]>
1
- -
+
-
false
@@ -26388,7 +26704,7 @@ return Component;]]>
true
1
-
-
+
-
false
@@ -26427,7 +26743,7 @@ return Component;]]>
true
1
-
-
+
-
false
@@ -26478,7 +26794,7 @@ return Component;]]>
1
- -
+
-
true
@@ -26544,7 +26860,7 @@ return Component;]]>
- -
+
-
false
@@ -26583,7 +26899,7 @@ return Component;]]>
true
1
-
-
+
-
false
@@ -26622,7 +26938,7 @@ return Component;]]>
true
1
-
-
+
-
true
@@ -26676,7 +26992,7 @@ return Component;]]>
2
- -
+
-
false
@@ -26737,7 +27053,7 @@ return Component;]]>
1
- -
+
-
false
@@ -26778,7 +27094,7 @@ return Component;]]>
- -
+
-
false
@@ -26830,7 +27146,7 @@ return Component;]]>
- -
+
-
false
@@ -26869,7 +27185,7 @@ return Component;]]>
true
1
-
-
+
-
false
@@ -26908,7 +27224,7 @@ return Component;]]>
true
1
-
-
+
-
true
@@ -26962,7 +27278,7 @@ return Component;]]>
2
- -
+
-
false
@@ -27023,7 +27339,7 @@ return Component;]]>