TimberWoods / src /ServerScriptService /DragManager.server.lua
algorembrant's picture
Upload 88 files
0712d5f verified
-- src/ServerScriptService/DragManager.server.lua
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local DraggingConfig = require(ReplicatedStorage:WaitForChild("Shared"):WaitForChild("DraggingConfig"))
local DragEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("DragEvent")
local DropEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("DropEvent")
-- Store active dragging states
local activeDrags = {}
-- Validate if the object can be dragged (e.g. TreeSegments, Logs, Furniture)
local function canBeDragged(part)
return CollectionService:HasTag(part, "Draggable") or CollectionService:HasTag(part, "TreeSegment")
end
-- Cleanup function when a player drops an object or disconnects
local function dropObject(player)
local dragData = activeDrags[player.UserId]
if dragData then
-- Clean up attachments and constraints
if dragData.dragAttachment then dragData.dragAttachment:Destroy() end
if dragData.targetAttachment then dragData.targetAttachment:Destroy() end
if dragData.alignPos then dragData.alignPos:Destroy() end
if dragData.alignOri then dragData.alignOri:Destroy() end
-- Reset Network Ownership to Server (or Auto)
if dragData.part and dragData.part:IsDescendantOf(workspace) then
-- Optional: Add a small impulse so it doesn't just freeze mid-air
pcall(function()
dragData.part:SetNetworkOwner(nil)
end)
end
activeDrags[player.UserId] = nil
end
end
-- Handle Drag Event Request
local function onDragRequest(player, targetPart, hitPoint)
if not targetPart or not targetPart:IsA("BasePart") then return end
if not canBeDragged(targetPart) then return end
local char = player.Character
if not char or not char:FindFirstChild("HumanoidRootPart") then return end
-- Distance verification
local distance = (char.HumanoidRootPart.Position - targetPart.Position).Magnitude
if distance > DraggingConfig.MaxGrabDistance then return end
-- Ensure player isn't already dragging something
if activeDrags[player.UserId] then dropObject(player) end
-- Verify the part isn't already being dragged by someone else
for _, dragData in pairs(activeDrags) do
if dragData.part == targetPart then return end
end
-- Setup Attachments and Constraints
local partAttachment = Instance.new("Attachment")
partAttachment.Name = "DragAttachment"
partAttachment.CFrame = targetPart.CFrame:ToObjectSpace(CFrame.new(hitPoint))
partAttachment.Parent = targetPart
-- We create a proxy attachment in Terrain, managed by the client later, or just update it via Server
-- For Smoothest results, we give the Client network ownership and let local physics do the dragging, but the Constraints exist Server-Side.
local targetAttachment = Instance.new("Attachment")
targetAttachment.Name = "TargetAttachment_Player" .. player.UserId
-- Setting it to character's Head/Camera relative position on the server initially
targetAttachment.WorldCFrame = CFrame.new(char.Head.Position + char.Head.CFrame.LookVector * DraggingConfig.HoldDistance)
targetAttachment.Parent = workspace.Terrain
local alignPos = Instance.new("AlignPosition")
alignPos.Attachment0 = partAttachment
alignPos.Attachment1 = targetAttachment
alignPos.MaxForce = DraggingConfig.AlignPositionMaxForce
alignPos.Responsiveness = DraggingConfig.AlignPositionResponsiveness
alignPos.Parent = targetPart
local alignOri = Instance.new("AlignOrientation")
alignOri.Attachment0 = partAttachment
alignOri.Attachment1 = targetAttachment
alignOri.MaxTorque = DraggingConfig.AlignOrientationMaxTorque
alignOri.Responsiveness = DraggingConfig.AlignOrientationResponsiveness
alignOri.Parent = targetPart
-- Grant Network Ownership to the Player to eliminate latency rubber-banding
pcall(function()
targetPart:SetNetworkOwner(player)
end)
-- Save the state
activeDrags[player.UserId] = {
part = targetPart,
dragAttachment = partAttachment,
targetAttachment = targetAttachment,
alignPos = alignPos,
alignOri = alignOri
}
end
-- Handle Drop Event Request
local function onDropRequest(player)
dropObject(player)
end
-- Players leaving cleanup
Players.PlayerRemoving:Connect(function(player)
dropObject(player)
end)
DragEvent.OnServerEvent:Connect(onDragRequest)
DropEvent.OnServerEvent:Connect(onDropRequest)