I made a mirror selection tool in a building game I’m making. Everything works correctly when rotated at 90 degrees, but it doesn’t mirror correctly when rotated.
Here I mirror 5 blocks rotated at 45 degrees. It creates a V shape instead of what should happen in the example below.
When I clone 5 blocks in Build A Boat For Treasure, it stacks them ontop of each other. This is what I’m trying to achieve.
I added a print for the positions variable before firing the remove function and it prints this:
["CFrame"] = 106, 22.1715851, 459.828461, 1, 0, 0, 0, 0.707134247, 0.707079291, 0,
Mirror tool script (client)
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local CollectionService = game:GetService("CollectionService")
local Workspace = game:GetService("Workspace")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Remotes = ReplicatedStorage:WaitForChild("Remotes")
local ValidateMirror = Remotes:WaitForChild("ValidateMirror")
local placedBlocks = workspace:WaitForChild("PlacedBlocks")
local player = Players.LocalPlayer
local pgui = player:WaitForChild("PlayerGui")
local mouse = player:GetMouse()
local selectionBox = script.SelectionBox
local handles = script.MoveHandles
local hoverBox = script.SelectionBoxHover
local playerModule = player.PlayerScripts.PlayerModule
local CameraInput = require(playerModule.CameraModule.CameraInput)
local ControlModule = require(playerModule.ControlModule)
local module = {}
local enabled = false
local dragging = false
local currentHandles
local boundingPart
local originalBoundingCFrame
local modelOffsets = {}
local selectedModels = require(script.Parent.Parent.GlobalFunctions.SelectedModels)
local renderConn, mouseDownConn
local handleMouseDownConn, handleMouseUpConn
local shiftDownIgnoreArrowsFlag = false
local shiftConnBegan, shiftConnEnded
local DragConnection, guiDragConn, guiDragEndConn
local Corner1 = Vector2.zero
local validateDebounce = false
local ScaleGui = script.MoveGui
local GuiStarted = false
local currentFace
local currentDistance
local currentFace
local modelSelectionBoxes = {}
local moveSelection = script.Selection_Mirror
local moveSelectionFrame = moveSelection:WaitForChild("Frame")
local selectionPool = {}
local function getSelectionVisual()
if #selectionPool > 0 then
local v = table.remove(selectionPool)
v.Parent = workspace
return v
end
local box = selectionBox:Clone()
box.Parent = workspace
return box
end
local function getScaledAmount(model, SelectedModels, useVector, SetSize)
if not model or not SelectedModels then return 1 end
local BlockId = model:GetAttribute("BLOCKID")
if not BlockId then return 1 end
local amount = 0
for _, block in ipairs(SelectedModels) do
if block:GetAttribute("BLOCKID") == BlockId then
local part = block:FindFirstChildWhichIsA("BasePart")
if part then
local size = part.Size
if useVector and SetSize then
if block == model then
size = SetSize
end
end
local blocksX = size.X / 2
local blocksY = size.Y / 2
local blocksZ = size.Z / 2
amount += math.max(1, math.round(blocksX * blocksY * blocksZ))
end
end
end
return amount
end
local function formatSize(num)
local rounded = math.floor(num * 1000 + 0.5) / 1000
local str = string.format("%.3f", rounded)
str = str:gsub("%.?0+$", "")
return str
end
local function isValidNumber(text, minValue, maxValue)
if not string.match(text, "^%d*%.?%d%d?%d?$") then
return false
end
local num = tonumber(text)
if not num then
return false
end
return num >= minValue and num <= maxValue
end
local function getBiggestNumberFromSize(vec)
local biggest = vec.X
if vec.Y > biggest then biggest = vec.Y end
if vec.Z > biggest then biggest = vec.Z end
return biggest
end
local function updateGui(textOnly)
local frame = ScaleGui:FindFirstChild("Frame")
if not frame then return end
local slot = frame:FindFirstChild("Slot")
if not slot then return end
local viewport = slot:FindFirstChild("BlockIcon")
if not viewport then return end
local amountText = slot:FindFirstChild("Amount")
if not amountText then return end
if #selectedModels.Selected > 0 then
amountText.Visible = true
if not textOnly then
for _, v in pairs(viewport:GetChildren()) do
if v:IsA("Model") then
v:Destroy()
end
end
local firstName = selectedModels.Selected[1].Name
local allSame = true
for _, model in ipairs(selectedModels.Selected) do
if model.Name ~= firstName then
allSame = false
break
end
end
local viewportBlock
if allSame then
local replicatedBlock = game.ReplicatedStorage:WaitForChild("Blocks"):FindFirstChild(firstName)
if replicatedBlock then
viewportBlock = replicatedBlock:Clone()
end
else
local templateBlock = game.ReplicatedStorage:WaitForChild("TemplateBlock")
viewportBlock = templateBlock:Clone()
end
if viewportBlock then
local orientation, size = viewportBlock:GetBoundingBox()
local cameraDistance = getBiggestNumberFromSize(size) * 1.5
viewportBlock:PivotTo(CFrame.new(0,0,cameraDistance) * CFrame.Angles(0, math.rad(45), math.rad(45)))
viewportBlock.Parent = viewport
end
end
local userFolder = placedBlocks:FindFirstChild(player.UserId)
if userFolder then
local countedBlocks = {}
local totalAmount = 0
for _, model in ipairs(selectedModels.Selected) do
local blockName = model.Name
if not countedBlocks[blockName] then
local amt = getScaledAmount(model, selectedModels.Selected)
countedBlocks[blockName] = amt
totalAmount += amt
end
end
amountText.Text = tostring(totalAmount)
end
else
amountText.Visible = false
for _, v in pairs(viewport:GetChildren()) do
if v:IsA("Model") then
v:Destroy()
end
end
end
end
local function clearSelection()
if validateDebounce then return end
selectedModels.Selected = {}
if boundingPart then
boundingPart:Destroy()
boundingPart = nil
end
if handleMouseDownConn then handleMouseDownConn:Disconnect() handleMouseDownConn = nil end
if handleMouseUpConn then handleMouseUpConn:Disconnect() handleMouseUpConn = nil end
if currentHandles then
currentHandles:Destroy()
currentHandles = nil
end
selectionBox.Parent = script
selectionBox.Adornee = nil
hoverBox.Parent = script
hoverBox.Adornee = nil
for model, box in pairs(modelSelectionBoxes) do
if box then
box:Destroy()
end
end
modelSelectionBoxes = {}
updateGui()
end
local function getBoundingBox(models)
if #models == 0 then return nil, nil end
local allCorners = {}
local lastModelPivot
for i, model in ipairs(models) do
local success, cf, size = pcall(function() return model:GetBoundingBox() end)
if success and cf and size then
local halfSize = size / 2
local corners = {
cf * Vector3.new(-halfSize.X,-halfSize.Y,-halfSize.Z),
cf * Vector3.new(-halfSize.X,-halfSize.Y, halfSize.Z),
cf * Vector3.new(-halfSize.X, halfSize.Y,-halfSize.Z),
cf * Vector3.new(-halfSize.X, halfSize.Y, halfSize.Z),
cf * Vector3.new( halfSize.X,-halfSize.Y,-halfSize.Z),
cf * Vector3.new( halfSize.X,-halfSize.Y, halfSize.Z),
cf * Vector3.new( halfSize.X, halfSize.Y,-halfSize.Z),
cf * Vector3.new( halfSize.X, halfSize.Y, halfSize.Z),
}
for _, corner in ipairs(corners) do
table.insert(allCorners, corner)
end
if i == #models then
local successPivot, pivot = pcall(function() return model:GetPivot() end)
lastModelPivot = (successPivot and pivot) or cf
end
end
end
if #allCorners == 0 then return nil, nil end
local invPivot = lastModelPivot:Inverse()
local localCorners = {}
for _, corner in ipairs(allCorners) do
table.insert(localCorners, invPivot * corner)
end
local minVec = localCorners[1]
local maxVec = localCorners[1]
for _, corner in ipairs(localCorners) do
minVec = Vector3.new(math.min(minVec.X, corner.X), math.min(minVec.Y, corner.Y), math.min(minVec.Z, corner.Z))
maxVec = Vector3.new(math.max(maxVec.X, corner.X), math.max(maxVec.Y, corner.Y), math.max(maxVec.Z, corner.Z))
end
local centerLocal = (minVec + maxVec) / 2
local size = maxVec - minVec
local boundingCFrame = lastModelPivot * CFrame.new(centerLocal)
return boundingCFrame, size
end
local function updateBoundingPart()
if #selectedModels.Selected == 0 then
if boundingPart then boundingPart:Destroy() end
boundingPart = nil
selectionBox.Adornee = nil
if currentHandles then
handleMouseDownConn:Disconnect() handleMouseDownConn = nil
handleMouseUpConn:Disconnect() handleMouseUpConn = nil
currentHandles:Destroy()
currentHandles = nil
end
return
end
local cf, size = getBoundingBox(selectedModels.Selected)
if not cf or not size then return end
if not boundingPart then
boundingPart = Instance.new("Part")
boundingPart.CanQuery = false
boundingPart.Anchored = true
boundingPart.Transparency = 1
boundingPart.CanCollide = false
boundingPart.Name = "MoveBoundingPart"
boundingPart.Parent = workspace
selectionBox.Parent = workspace
selectionBox.Adornee = boundingPart
end
boundingPart.CFrame = cf
boundingPart.Size = size
end
local function toggleSelection(model, shift, touchEnabled)
local owner = model:GetAttribute("Owner")
if owner ~= player.UserId then return end
if validateDebounce then return end
if #selectedModels.Selected > 1 and not shift and not touchEnabled then
clearSelection()
toggleSelection(model)
return
end
local idx = table.find(selectedModels.Selected, model)
if idx then
table.remove(selectedModels.Selected, idx)
if modelSelectionBoxes[model] then
modelSelectionBoxes[model]:Destroy()
modelSelectionBoxes[model] = nil
end
else
table.insert(selectedModels.Selected, model)
local box = selectionBox:Clone()
box.Adornee = model
box.Parent = workspace
modelSelectionBoxes[model] = box
end
updateBoundingPart()
updateGui()
end
local function beginMove()
if not boundingPart or validateDebounce or shiftDownIgnoreArrowsFlag then return end
dragging = true
local boundingBoxCFrame = boundingPart.CFrame
if not boundingBoxCFrame then
warn("BoundingPart has no CFrame")
dragging = false
return
end
originalBoundingCFrame = boundingBoxCFrame
modelOffsets = {}
for _, model in ipairs(selectedModels.Selected) do
if model and model:IsA("Model") then
local modelCFrame, _ = model:GetBoundingBox()
if modelCFrame then
modelOffsets[model] = originalBoundingCFrame:ToObjectSpace(modelCFrame)
else
local primary = model.PrimaryPart
if primary then
modelOffsets[model] = originalBoundingCFrame:ToObjectSpace(primary.CFrame)
else
warn("Model has no parts or bounding box:", model:GetFullName())
end
end
end
end
if UserInputService.TouchEnabled then
CameraInput.setInputEnabled(false)
ControlModule:Disable()
end
end
local function selectNewBlocks(newBlocks)
for _, box in pairs(modelSelectionBoxes) do
if box and box.Parent then
box:Destroy()
end
end
modelSelectionBoxes = {}
selectedModels.Selected = {}
if enabled == true then
for _, model in ipairs(newBlocks) do
table.insert(selectedModels.Selected, model)
local box = selectionBox:Clone()
box.Adornee = model.PrimaryPart or model
box.Parent = workspace
modelSelectionBoxes[model] = box
end
updateBoundingPart()
modelOffsets = {}
if boundingPart then
for _, model in ipairs(selectedModels.Selected) do
if model.PrimaryPart then
modelOffsets[model] = boundingPart.CFrame:ToObjectSpace(model.PrimaryPart.CFrame)
end
end
end
updateGui()
end
end
local function endMove()
if not boundingPart or not dragging then return end
if validateDebounce then return end
dragging = false
validateDebounce = true
CameraInput.setInputEnabled(true)
ControlModule:Enable()
local positions = {}
for model, offset in pairs(modelOffsets) do
if typeof(offset) == "CFrame" and boundingPart and boundingPart.CFrame then
table.insert(positions, {Model = model, CFrame = boundingPart.CFrame * offset})
else
if model and model:IsA("Model") then
local success, modelCFrame = pcall(function() return model:GetBoundingBox() end)
if success and modelCFrame and originalBoundingCFrame then
local fallbackOffset = originalBoundingCFrame:ToObjectSpace(modelCFrame)
if typeof(fallbackOffset) == "CFrame" and boundingPart and boundingPart.CFrame then
table.insert(positions, {Model = model, CFrame = boundingPart.CFrame * fallbackOffset})
end
end
end
end
end
local result
pcall(function()
print(positions)
result = ValidateMirror:InvokeServer(positions, currentFace)
end)
if not result or not result.Success then
if originalBoundingCFrame then
boundingPart.CFrame = originalBoundingCFrame
end
script.Reject:Play()
end
if result and result.newBlocks then
selectNewBlocks(result.newBlocks)
end
validateDebounce = false
end
local function updateHover()
if UserInputService.TouchEnabled then return end
if not mouse.Target then
hoverBox.Adornee = nil
return
end
local target = mouse.Target
local model = target:FindFirstAncestorOfClass("Model")
if model then
local owner = model:GetAttribute("Owner")
if model:IsDescendantOf(workspace.PlacedBlocks:FindFirstChild(player.UserId)) and owner == player.UserId then
hoverBox.Parent = workspace
hoverBox.Adornee = model.PrimaryPart or target
else
hoverBox.Adornee = nil
end
else
hoverBox.Adornee = nil
end
end
local function updateHandlesParent()
if currentHandles then
currentHandles.Parent = shiftDownIgnoreArrowsFlag and workspace or pgui
end
end
local function onClick()
if validateDebounce then return end
if not mouse.Target then return end
local model = mouse.Target:FindFirstAncestorOfClass("Model")
if not model then return end
if UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift) or UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) or UserInputService:IsKeyDown(Enum.KeyCode.RightControl) or UserInputService.TouchEnabled then
toggleSelection(model, true, UserInputService.TouchEnabled)
else
if not table.find(selectedModels.Selected, model) then
clearSelection()
end
toggleSelection(model, false, UserInputService.TouchEnabled)
end
if boundingPart then
if currentHandles then
handleMouseDownConn:Disconnect() handleMouseDownConn = nil
handleMouseUpConn:Disconnect() handleMouseUpConn = nil
currentHandles:Destroy()
currentHandles = nil
end
currentHandles = handles:Clone()
currentHandles.Adornee = boundingPart
currentHandles.Style = Enum.HandlesStyle.Movement
updateHandlesParent()
handleMouseDownConn = currentHandles.MouseButton1Down:Connect(beginMove)
handleMouseUpConn = currentHandles.MouseButton1Up:Connect(function(face)
currentFace = face
endMove()
end)
end
end
local function selectCurrentModels()
if not enabled then return end
if not selectedModels.Selected then return end
for model, box in pairs(modelSelectionBoxes) do
if box then
box:Destroy()
end
end
modelSelectionBoxes = {}
for i = #selectedModels.Selected, 1, -1 do
local model = selectedModels.Selected[i]
if not model or not model:IsDescendantOf(workspace) then
table.remove(selectedModels.Selected, i)
end
end
for _, model in ipairs(selectedModels.Selected) do
local box = selectionBox:Clone()
box.Adornee = model.PrimaryPart or model
box.Parent = workspace
modelSelectionBoxes[model] = box
end
updateBoundingPart()
if boundingPart and boundingPart:IsDescendantOf(workspace) then
if currentHandles then
if handleMouseDownConn then handleMouseDownConn:Disconnect() end
if handleMouseUpConn then handleMouseUpConn:Disconnect() end
currentHandles:Destroy()
currentHandles = nil
end
currentHandles = handles:Clone()
currentHandles.Adornee = boundingPart
currentHandles.Style = Enum.HandlesStyle.Movement
updateHandlesParent()
handleMouseDownConn = currentHandles.MouseButton1Down:Connect(beginMove)
handleMouseUpConn = currentHandles.MouseButton1Up:Connect(function(face)
currentFace = face
endMove()
end)
end
updateGui()
end
function module.Enable()
if enabled then return end
enabled = true
GuiStarted = false
if renderConn then renderConn:Disconnect() renderConn = nil end
if mouseDownConn then mouseDownConn:Disconnect() mouseDownConn = nil end
renderConn = RunService.RenderStepped:Connect(updateHover)
mouseDownConn = mouse.Button1Down:Connect(onClick)
shiftConnBegan = UserInputService.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Keyboard and (input.KeyCode == Enum.KeyCode.LeftShift or input.KeyCode == Enum.KeyCode.RightShift or input.KeyCode == Enum.KeyCode.LeftControl or input.KeyCode == Enum.KeyCode.RightControl) then
shiftDownIgnoreArrowsFlag = true
updateHandlesParent()
end
end)
shiftConnEnded = UserInputService.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Keyboard and (input.KeyCode == Enum.KeyCode.LeftShift or input.KeyCode == Enum.KeyCode.RightShift or input.KeyCode == Enum.KeyCode.LeftControl or input.KeyCode == Enum.KeyCode.RightControl) then
shiftDownIgnoreArrowsFlag = false
updateHandlesParent()
end
end)
local MIN_DRAG_DISTANCE = 5
local DraggingActive = false
local Corner1 = Vector2.new()
local tempModelSelect = {}
guiDragConn = UserInputService.InputBegan:Connect(function(input, gameProcessed)
if input.UserInputType ~= Enum.UserInputType.MouseButton1 or gameProcessed then return end
Corner1 = Vector2.new(mouse.X, mouse.Y) -- raw mouse pos
DraggingActive = false
local guiInset = game:GetService("GuiService"):GetGuiInset()
if DragConnection then DragConnection:Disconnect() end
DragConnection = UserInputService.InputChanged:Connect(function(inputObject)
if inputObject.UserInputType ~= Enum.UserInputType.MouseMovement then return end
local currentPos = Vector2.new(mouse.X, mouse.Y) -- raw mouse pos
local delta = (currentPos - Corner1).magnitude
if not DraggingActive and delta >= MIN_DRAG_DISTANCE then
DraggingActive = true
moveSelection.Parent = pgui
moveSelectionFrame.Position = UDim2.fromOffset(Corner1.X, Corner1.Y)
moveSelectionFrame.Size = UDim2.fromOffset(0, 0)
if not UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) and not UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) and not UserInputService:IsKeyDown(Enum.KeyCode.RightShift) and not UserInputService:IsKeyDown(Enum.KeyCode.RightControl) then
clearSelection()
end
end
if DraggingActive then
local size = currentPos - Corner1
local pos = Corner1 + Vector2.new(math.min(0, size.X), math.min(0, size.Y))
local absSize = Vector2.new(math.abs(size.X), math.abs(size.Y))
moveSelectionFrame.Position = UDim2.fromOffset(pos.X, pos.Y)
moveSelectionFrame.Size = UDim2.fromOffset(absSize.X, absSize.Y)
local userFolder = placedBlocks:FindFirstChild(player.UserId)
if not userFolder then return end
for _, model in ipairs(userFolder:GetChildren()) do
local owner = model:GetAttribute("Owner")
if model:IsA("Model") and owner == player.UserId then
local cf, size = model:GetBoundingBox()
local corners = {
cf * Vector3.new(-size.X/2, -size.Y/2, -size.Z/2),
cf * Vector3.new(-size.X/2, -size.Y/2, size.Z/2),
cf * Vector3.new(-size.X/2, size.Y/2, -size.Z/2),
cf * Vector3.new(-size.X/2, size.Y/2, size.Z/2),
cf * Vector3.new( size.X/2, -size.Y/2, -size.Z/2),
cf * Vector3.new( size.X/2, -size.Y/2, size.Z/2),
cf * Vector3.new( size.X/2, size.Y/2, -size.Z/2),
cf * Vector3.new( size.X/2, size.Y/2, size.Z/2),
}
local minScreen, maxScreen
for _, corner in ipairs(corners) do
local screenPos, onScreen = workspace.CurrentCamera:WorldToViewportPoint(corner)
if onScreen and screenPos.Z > 0 then
local pos2D = Vector2.new(screenPos.X, screenPos.Y - guiInset.Y)
if not minScreen then
minScreen, maxScreen = pos2D, pos2D
else
minScreen = Vector2.new(math.min(minScreen.X, pos2D.X), math.min(minScreen.Y, pos2D.Y))
maxScreen = Vector2.new(math.max(maxScreen.X, pos2D.X), math.max(maxScreen.Y, pos2D.Y))
end
end
end
if minScreen and maxScreen then
local inRect = maxScreen.X >= pos.X and minScreen.X <= pos.X + absSize.X and
maxScreen.Y >= pos.Y and minScreen.Y <= pos.Y + absSize.Y
if inRect then
if not modelSelectionBoxes[model] then
local box = selectionBox:Clone()
box.Adornee = model
box.Parent = workspace
modelSelectionBoxes[model] = box
end
else
if modelSelectionBoxes[model] and not table.find(selectedModels.Selected, model) then
modelSelectionBoxes[model]:Destroy()
modelSelectionBoxes[model] = nil
end
end
end
end
end
end
end)
end)
guiDragEndConn = UserInputService.InputEnded:Connect(function(input, gameProcessed)
if not (input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch) then
return
end
moveSelection.Parent = script
if DragConnection then
DragConnection:Disconnect()
DragConnection = nil
end
if not DraggingActive then
return
end
DraggingActive = false
local finalModels = {}
for model, box in pairs(modelSelectionBoxes) do
if model and typeof(model) == "Instance" and model:IsA("Model") and box then
table.insert(finalModels, model)
end
end
local modifierDown = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift)
or UserInputService:IsKeyDown(Enum.KeyCode.RightShift)
or UserInputService:IsKeyDown(Enum.KeyCode.LeftControl)
or UserInputService:IsKeyDown(Enum.KeyCode.RightControl)
if not modifierDown then
clearSelection()
end
for _, model in ipairs(finalModels) do
if model and model:IsDescendantOf(workspace) and model:GetAttribute("Owner") == player.UserId then
if not table.find(selectedModels.Selected, model) then
table.insert(selectedModels.Selected, model)
end
if not modelSelectionBoxes[model] then
local box = getSelectionVisual()
box.Adornee = model.PrimaryPart or model
modelSelectionBoxes[model] = box
end
end
end
updateBoundingPart()
updateGui()
if boundingPart then
if currentHandles then
if handleMouseDownConn then handleMouseDownConn:Disconnect() handleMouseDownConn = nil end
if handleMouseUpConn then handleMouseUpConn:Disconnect() handleMouseUpConn = nil end
currentHandles:Destroy()
currentHandles = nil
end
currentHandles = handles:Clone()
currentHandles.Adornee = boundingPart
currentHandles.Style = Enum.HandlesStyle.Movement
updateHandlesParent()
handleMouseDownConn = currentHandles.MouseButton1Down:Connect(beginMove)
handleMouseUpConn = currentHandles.MouseButton1Up:Connect(function(face)
currentFace = face
endMove()
end)
end
end)
selectCurrentModels()
updateGui()
ScaleGui.Parent = pgui
end
function module.Disable()
if not enabled then return end
enabled = false
if renderConn then renderConn:Disconnect() renderConn = nil end
if mouseDownConn then mouseDownConn:Disconnect() mouseDownConn = nil end
if shiftConnBegan then shiftConnBegan:Disconnect() shiftConnBegan = nil end
if shiftConnEnded then shiftConnEnded:Disconnect() shiftConnEnded = nil end
shiftDownIgnoreArrowsFlag = false
--validateDebounce = false
dragging = false
if handleMouseDownConn then handleMouseDownConn:Disconnect() handleMouseDownConn = nil end
if handleMouseUpConn then handleMouseUpConn:Disconnect() handleMouseUpConn = nil end
if guiDragConn then guiDragConn:Disconnect() guiDragConn = nil end
if guiDragEndConn then guiDragEndConn:Disconnect() guiDragEndConn = nil end
if DragConnection then DragConnection:Disconnect() DragConnection = nil end
moveSelection.Parent = script
ScaleGui.Parent = script
--clearSelection()
if currentHandles then
currentHandles:Destroy()
currentHandles = nil
end
if boundingPart then
boundingPart:Destroy()
boundingPart = nil
end
--selectedModels = {}
selectionBox.Parent = script
selectionBox.Adornee = nil
hoverBox.Parent = script
hoverBox.Adornee = nil
for model, box in pairs(modelSelectionBoxes) do
if box then
box:Destroy()
end
end
modelSelectionBoxes = {}
CameraInput.setInputEnabled(true)
ControlModule:Enable()
end
return module
Any help is appreciated since I have a really hard time understanding CFrames ![]()