Secure Item Dragging System

I am trying to create a physics-based item dragging system like the one in Lumber Tycoon 2. I have already made an unsecure, fully client-controlled system that works. The issue I’m having is security. I am using align positions and orientations to move the part, and want there to be a max force, torque, velocity, etc. Currently, the client controls everything, so someone could easily change the values, or just teleport the part wherever they want. I have a server script that automatically sets the part’s networkownership to the player. How can I secure this so players cannot change the physics limits applied to the part, and cannot teleport the part when they have ownership?

Here is my current code


local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PlayersService = game:GetService("Players")
local RunService = game:GetService("RunService")
local UIS = game:GetService("UserInputService")

local Player = PlayersService.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid") :: Humanoid
local RootPart = Character:WaitForChild("HumanoidRootPart") :: BasePart

local Camera = workspace.CurrentCamera
local Mouse = Player:GetMouse()

local Responsiveness = 60

local MaxForce = 60000
local MaxTorque = 30000

local MaxVelocity = 40
local MaxAngularVelocity = 20

local MaxGrabDistance = 12
local MaxHoldDistance = 8
local MinHoldDistance = 3

local HoldingDistance = 6

local RotationMultiplier = 4
local DistanceChangeMultiplier = 2

local DraggableObjectTag = "Draggable"

local Dragging = false

local DraggingPart = nil
local Constraints = {
	AlignPosition = nil, 
	AlignOrientation = nil,
	Attachment = nil
}

local Keybinds = {
	Rotate = Enum.KeyCode.R,
	IncreaseDistance = Enum.KeyCode.X,
	DecreaseDistance = Enum.KeyCode.Z,
	Throw = Enum.KeyCode.F
}

local RotationOffset = CFrame.new(0, 0, 0)

local CFrameConnection = nil

local function HoveringDraggablePart()
	local Part = Mouse.Target	
	if not Part or not CollectionService:HasTag(Part, DraggableObjectTag) then return end
	
	local Distance = (Part.Position - RootPart.Position).Magnitude
	if Distance > MaxGrabDistance then return end
	
	return Part, Distance, Mouse.Hit.Position
end

local function BuildConstraints(grabPos)
	local Attachment = Instance.new("Attachment")
	Attachment.Parent = DraggingPart
	Attachment.WorldPosition = grabPos

	local AlignPosition = Instance.new("AlignPosition")
	AlignPosition.Parent = DraggingPart
	AlignPosition.Mode = Enum.PositionAlignmentMode.OneAttachment
	AlignPosition.Attachment0 = Attachment
	AlignPosition.MaxForce = MaxForce
	AlignPosition.MaxVelocity = MaxVelocity
	AlignPosition.Responsiveness = Responsiveness
	
	local AlignOrientation = Instance.new("AlignOrientation")
	AlignOrientation.Parent = DraggingPart
	AlignOrientation.Mode = Enum.OrientationAlignmentMode.OneAttachment
	AlignOrientation.Attachment0 = Attachment
	AlignOrientation.MaxTorque = MaxTorque
	AlignOrientation.MaxAngularVelocity = MaxAngularVelocity
	AlignOrientation.Responsiveness = Responsiveness
	
	Constraints.Attachment = Attachment
	Constraints.AlignPosition = AlignPosition
	Constraints.AlignOrientation = AlignOrientation
end

local function DestroyConstraints()
	for _, constraint in Constraints do
		if constraint then constraint:Destroy() end
	end
end

local function UpdateDraggingCFrame()
	if UIS:IsKeyDown(Keybinds.IncreaseDistance) then
		HoldingDistance = math.clamp(HoldingDistance + 0.1 * DistanceChangeMultiplier, MinHoldDistance, MaxHoldDistance)
	end
	
	if UIS:IsKeyDown(Keybinds.DecreaseDistance) then
		HoldingDistance = math.clamp(HoldingDistance - 0.1 * DistanceChangeMultiplier, MinHoldDistance, MaxHoldDistance)
	end
	
	if UIS:IsKeyDown(Keybinds.Rotate) then
		Humanoid.WalkSpeed = 0
		
		local RotationDelta = CFrame.new()
		
		if UIS:IsKeyDown(Enum.KeyCode.W) then
			RotationDelta *= CFrame.Angles(-0.01 * RotationMultiplier, 0, 0)
		end
		
		if UIS:IsKeyDown(Enum.KeyCode.S) then
			RotationDelta *= CFrame.Angles(0.01 * RotationMultiplier, 0, 0)
		end
		
		if UIS:IsKeyDown(Enum.KeyCode.A) then
			RotationDelta *= CFrame.Angles(0, 0.01 * RotationMultiplier, 0)
		end
		
		if UIS:IsKeyDown(Enum.KeyCode.D) then
			RotationDelta *= CFrame.Angles(0, -0.01 * RotationMultiplier, 0)
		end
		
		if UIS:IsKeyDown(Enum.KeyCode.E) then
			RotationDelta *= CFrame.Angles(0, 0, -0.01 * RotationMultiplier)
		end
		
		if UIS:IsKeyDown(Enum.KeyCode.Q) then
			RotationDelta *= CFrame.Angles(0, 0, 0.01 * RotationMultiplier)
		end
		
		RotationOffset *= RotationDelta
	else
		if Humanoid.WalkSpeed == 0 then 
			Humanoid.WalkSpeed = 16
		end
	end
	
	Mouse.TargetFilter = DraggingPart
	
	local Direction = CFrame.lookAt(DraggingPart.Position, Vector3.new(RootPart.Position.X, DraggingPart.Position.Y, RootPart.Position.Z))
	local DragVector = CFrame.new((RootPart.CFrame * CFrame.new(0, 2, 0).Position), Mouse.Hit.Position)
	
	local Position = (DragVector + (DragVector.LookVector * HoldingDistance)).Position
	local Rotation = Direction * RotationOffset
	
	Constraints.AlignPosition.Position = Position
	Constraints.AlignOrientation.CFrame = Rotation
	
	Mouse.TargetFilter = nil
end

local function GrabPart(part, distance, grabPosition)
	if Dragging then return end
	Dragging = true
	
	HoldingDistance = math.clamp(distance, MinHoldDistance, MaxHoldDistance)
	
	DraggingPart = part
	RotationOffset = CFrame.lookAt(part.Position, Vector3.new(RootPart.Position.X, part.Position.Y, RootPart.Position.Z)):ToObjectSpace(part.CFrame).Rotation
	
	BuildConstraints(grabPosition)
	CFrameConnection = RunService.RenderStepped:Connect(UpdateDraggingCFrame)
end

local function ReleasePart()
	if not Dragging then return end
	Dragging = false
	
	DraggingPart = nil
	
	DestroyConstraints()
	CFrameConnection:Disconnect()
end

Mouse.Button1Down:Connect(function()
	local Part, Distance, GrabPosition = HoveringDraggablePart()
	
	print(Part, Distance, GrabPosition)
	
	if Part then
		GrabPart(Part, Distance, GrabPosition)
	end
end)

Mouse.Button1Up:Connect(function()
	if Dragging then
		ReleasePart()
	end
end)

I’m largely asking how I can organize my scripts to make this work. I know I’ll likely have to rework the majority of my code, which I’m more than willing to do.