UserInputService.InputEnded:connect(function(w,I)if w.UserInputType~=Enum.UserInputType.MouseButton1 then return end if DragStart then DragStart=nil DragStartTarget=nil ClearConnection("\087\097\116\099\104\070\111\114\068\114\097\103")end if Dragging then SetAxes(MoveTool.Axes)FinishDragging()end end)function SetUpDragging(w,I)Core.Targeting.CancelSelecting()InitialState=PreparePartsForDragging()StartDragging(w,InitialState,I)end MoveTool.SetUpDragging=SetUpDragging function PreparePartsForDragging()local w={}local I=Support.FlipTable(Selection.Items)for y,p in pairs(Selection.Items)do w[p]={Anchored=p.Anchored;CanCollide=p.CanCollide;CFrame=p.CFrame}p.Anchored=true p.CanCollide=false w[p].Joints=Core.PreserveJoints(p,I)p:BreakJoints()p.Velocity=Vector3.new()p.RotVelocity=Vector3.new()end return w end function StartDragging(w,I,y)if Dragging then return end Dragging=true TrackChange()BoundingBox.ClearBoundingBox()local p if Core.Mode=="\084\111\111\108"then p=Security.GetPermissions(Security.GetSelectionAreas(Selection.Items),Core.Player)end if not w or not I[w]then return end local x=-w.CFrame:pointToObjectSpace(Core.Mouse.Hit.p)x=Vector3.new(math.clamp(GetIncrementMultiple(x.X,MoveTool.Increment),-w.Size.X/2,w.Size.X/2),math.clamp(GetIncrementMultiple(x.Y,MoveTool.Increment),-w.Size.Y/2,w.Size.Y/2),math.clamp(GetIncrementMultiple(x.Z,MoveTool.Increment),-w.Size.Z/2,w.Size.Z/2))if y then x=-w.CFrame:pointToObjectSpace(y)end SnapTracking.TargetBlacklist=Selection.Items Connections.DragSnapping=PointSnapped:connect(function(y)local X=SurfaceAlignment or I[w].CFrame-I[w].CFrame.p w.CFrame=(CFrame.new(y)*X)*CFrame.new(x)TranslatePartsRelativeToPart(w,I)if Core.Mode=="\084\111\111\108"and Security.ArePartsViolatingAreas(Selection.Items,Core.Player,false,p)then w.CFrame=I[w].CFrame TranslatePartsRelativeToPart(w,I)end end)CornerOffsets=GetCornerOffsets(I[w].CFrame,I)TriggerAlignment=function()DragToMouse(w,x,I,p)if SnapTracking.Enabled then PointSnapped:fire(SnappedPoint)end end Connections.Drag=Core.Mouse.Move:connect(function()DragToMouse(w,x,I,p)end)end
-- Catch whenever the user finishes dragging
UserInputService.InputEnded:connect(function(InputInfo, GameProcessedEvent)
	-- Make sure this was button 1 being released
	if InputInfo.UserInputType ~= Enum.UserInputType.MouseButton1 then
		return
	end

	-- Clean up dragging detection listeners and data
	if DragStart then
		-- Clear dragging detection data
		DragStart = nil
		DragStartTarget = nil

		-- Disconnect dragging initiation listeners
		ClearConnection("WatchForDrag")
	end

	-- Reset from drag mode if dragging
	if Dragging then
		-- Reset normal axes option state
		SetAxes(MoveTool.Axes)

		-- Finalize the dragging operation
		FinishDragging()
	end
end)

function SetUpDragging(BasePart, BasePoint)
	-- Sets up and initiates dragging based on the given base part

	-- Prevent selection while dragging
	Core.Targeting.CancelSelecting()

	-- Prepare parts, and start dragging
	InitialState = PreparePartsForDragging()
	StartDragging(BasePart, InitialState, BasePoint)
end

MoveTool.SetUpDragging = SetUpDragging

function PreparePartsForDragging()
	-- Prepares parts for dragging and returns the initial state of the parts

	local InitialState = {}

	-- Get index of parts
	local PartIndex = Support.FlipTable(Selection.Items)

	-- Stop parts from moving, and capture the initial state of the parts
	for _, Part in pairs(Selection.Items) do
		InitialState[Part] = { Anchored = Part.Anchored, CanCollide = Part.CanCollide, CFrame = Part.CFrame }
		Part.Anchored = true
		Part.CanCollide = false
		InitialState[Part].Joints = Core.PreserveJoints(Part, PartIndex)
		Part:BreakJoints()
		Part.Velocity = Vector3.new()
		Part.RotVelocity = Vector3.new()
	end

	return InitialState
end

function StartDragging(BasePart, InitialState, BasePoint)
	-- Begins dragging the selection

	-- Ensure dragging is not already ongoing
	if Dragging then
		return
	end

	-- Indicate that we're dragging
	Dragging = true

	-- Track changes
	TrackChange()

	-- Disable bounding box calculation
	BoundingBox.ClearBoundingBox()

	-- Cache area permissions information
	local AreaPermissions
	if Core.Mode == "Tool" then
		AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Selection.Items), Core.Player)
	end

	-- Ensure a base part is provided
	if not BasePart or not InitialState[BasePart] then
		return
	end

	-- Determine the base point for dragging
	local BasePartOffset = -BasePart.CFrame:pointToObjectSpace(Core.Mouse.Hit.p)

	-- Improve base point alignment for the given increment
	BasePartOffset = Vector3.new(
		math.clamp(
			GetIncrementMultiple(BasePartOffset.X, MoveTool.Increment),
			-BasePart.Size.X / 2,
			BasePart.Size.X / 2
		),
		math.clamp(
			GetIncrementMultiple(BasePartOffset.Y, MoveTool.Increment),
			-BasePart.Size.Y / 2,
			BasePart.Size.Y / 2
		),
		math.clamp(
			GetIncrementMultiple(BasePartOffset.Z, MoveTool.Increment),
			-BasePart.Size.Z / 2,
			BasePart.Size.Z / 2
		)
	)

	-- Use the given base point instead if any
	if BasePoint then
		BasePartOffset = -BasePart.CFrame:pointToObjectSpace(BasePoint)
	end

	-- Prepare snapping in case it is enabled, and make sure to override its default target selection
	SnapTracking.TargetBlacklist = Selection.Items
	Connections.DragSnapping = PointSnapped:connect(function(SnappedPoint)
		-- Align the selection's base point to the snapped point
		local Rotation = SurfaceAlignment or (InitialState[BasePart].CFrame - InitialState[BasePart].CFrame.p)
		BasePart.CFrame = CFrame.new(SnappedPoint) * Rotation * CFrame.new(BasePartOffset)
		TranslatePartsRelativeToPart(BasePart, InitialState)

		-- Make sure we're not entering any unauthorized private areas
		if
			Core.Mode == "Tool"
			and Security.ArePartsViolatingAreas(Selection.Items, Core.Player, false, AreaPermissions)
		then
			BasePart.CFrame = InitialState[BasePart].CFrame
			TranslatePartsRelativeToPart(BasePart, InitialState)
		end
	end)

	-- Update cache of corner offsets for later crossthrough calculations
	CornerOffsets = GetCornerOffsets(InitialState[BasePart].CFrame, InitialState)

	-- Provide a callback to trigger alignment
	TriggerAlignment = function()
		-- Trigger drag recalculation
		DragToMouse(BasePart, BasePartOffset, InitialState, AreaPermissions)

		-- Trigger snapping recalculation
		if SnapTracking.Enabled then
			PointSnapped:fire(SnappedPoint)
		end
	end

	-- Start up the dragging action
	Connections.Drag = Core.Mouse.Move:connect(function()
		DragToMouse(BasePart, BasePartOffset, InitialState, AreaPermissions)
	end)
end
