So basically I am importing a drag script kinda like dead rails to another game like my friend told me too. I imported 100% correctly but for some reason. it does not let me drag the part. It is caught on the server and returning true and everything but the part won’t move. I even copied a part from the test game into the real one to see and it still did not work.
– Client code
-- Services
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Modules
local ActionManager = require(ReplicatedStorage.Modules.ActionManager)
-- References
local dragTarg = workspace.Terrain.Drag
print("DIAGNOSTIC 1: The 'dragTarg' variable is:", dragTarg)
local camera = workspace.CurrentCamera
local plr = Players.LocalPlayer
local DragFunction = ReplicatedStorage:WaitForChild("DragFunction")
local WeldRemote = ReplicatedStorage:WaitForChild("Weld")
-- Config
local maxDistance = 15
local rotationSpeed = 90
-- State Vars
local target = nil
local grabbedOBJ = nil
local distance = 0
local isRotating = false
local accumulatedRotation = CFrame.new()
local currentAxis = 1
local axisNames = {"X", "Y", "Z"}
local isMobile = UserInputService.TouchEnabled
local currentTouchPosition = nil
local isPointerOverGui = false
local recentlyDroppedPart = nil
local recentlyDroppedTimestamp = 0
local activeActions = {}
local MobileUI, MainFrame, DragButton, DropButton, RotateButton, ChangeAxisButton, WeldButton
pcall(function()
MobileUI = plr.PlayerGui:WaitForChild("Mobile", 5)
if not MobileUI then return end
MainFrame = MobileUI:WaitForChild("Frame", 2)
if not MainFrame then return end
DragButton = MainFrame:WaitForChild("Drag", 2)
DropButton = MainFrame:WaitForChild("Drop", 2)
RotateButton = MainFrame:WaitForChild("Rotate", 2)
ChangeAxisButton = MainFrame:WaitForChild("ChangeAxis", 2)
WeldButton = MainFrame:WaitForChild("Weld", 2)
end)
if MobileUI then
MobileUI.Enabled = isMobile
end
local function isWeldable(obj)
if not obj then return false end
local current = obj
while current and current ~= workspace do
if current:FindFirstChild("Weldable") then
return true
end
current = current.Parent
end
return false
end
local function getWeldedParts(part)
local weldedParts = {}
if not part then return weldedParts end
for _, constraint in ipairs(part:GetChildren()) do
if constraint:IsA("WeldConstraint") then
local otherPart = (constraint.Part0 == part and constraint.Part1) or constraint.Part0
if otherPart and otherPart ~= part and not table.find(weldedParts, otherPart) then
table.insert(weldedParts, otherPart)
end
end
end
return weldedParts
end
local function getClosestWeldablePart(centerPart)
if not (centerPart and centerPart:IsA("BasePart")) then return nil end
local closestPart, closestDistanceFound = nil, 3.5
local maxSearchDistance = 3.5
local overlapParams = OverlapParams.new()
overlapParams.FilterType = Enum.RaycastFilterType.Exclude
overlapParams.FilterDescendantsInstances = {centerPart}
local candidates = workspace:GetPartBoundsInRadius(centerPart.Position, maxSearchDistance, overlapParams)
for _, otherPart in ipairs(candidates) do
if otherPart:IsA("BasePart") and isWeldable(otherPart) then
local dist = (otherPart.Position - centerPart.Position).Magnitude
if dist < closestDistanceFound then
closestDistanceFound = dist
closestPart = otherPart
end
end
end
return closestPart
end
local function checkAttachment(obj)
local attachment = obj:FindFirstChild("DragAttachment")
if not attachment then
attachment = Instance.new("Attachment")
attachment.Name = "DragAttachment"
attachment.Parent = obj
end
return attachment
end
function HighlightObj(obj, enableUI)
script.Highlight.Adornee = obj
local ui = script.BillboardGui
ui.Adornee = obj
ui.Enabled = enableUI
if obj then
ui.ItemName.Text = obj.Name
if obj:HasTag("Valuable") then
ui.Type.Text = "Valuable"
elseif obj:HasTag("Fuel") then
ui.Type.Text = "Fuel"
elseif isWeldable(obj) then
ui.Type.Text = "Weldable"
else
ui.Type.Text = "Junk"
end
end
end
function dropObj()
if not grabbedOBJ then return end
recentlyDroppedPart = grabbedOBJ
recentlyDroppedTimestamp = os.clock()
HighlightObj(nil, false)
DragFunction:InvokeServer(grabbedOBJ, false)
if grabbedOBJ then
grabbedOBJ.CollisionGroup = "Default"
end
grabbedOBJ = nil
isRotating = false
script.AlignOrientation.Attachment0 = nil
script.AlignPosition.Attachment0 = nil
end
function grabAction()
if target and not grabbedOBJ then
if DragFunction:InvokeServer(target, true) then
grabbedOBJ = target
print("DIAGNOSTIC 2: Client believes it has grabbed object:", grabbedOBJ.Name)
grabbedOBJ.CollisionGroup = "DragCollision"
distance = (camera.CFrame.Position - grabbedOBJ.Position).Magnitude
accumulatedRotation = CFrame.new()
target = nil
end
end
end
function dropAction()
if grabbedOBJ then
dropObj()
end
end
function rotateAction(start)
if grabbedOBJ then
isRotating = start
end
end
function changeAxisAction()
if grabbedOBJ then
currentAxis = (currentAxis % 3) + 1
end
end
function weldAction()
if grabbedOBJ and isWeldable(grabbedOBJ) then
local weldedParts = getWeldedParts(grabbedOBJ)
if #weldedParts > 0 then
for _, weldedPart in ipairs(weldedParts) do
WeldRemote:FireServer(grabbedOBJ, weldedPart, false)
end
else
local closestPart = getClosestWeldablePart(grabbedOBJ)
if closestPart then
WeldRemote:FireServer(grabbedOBJ, closestPart, true)
task.wait(0.05)
dropObj()
end
end
elseif target and isWeldable(target) and not grabbedOBJ then
local weldedParts = getWeldedParts(target)
if #weldedParts > 0 then
for _, weldedPart in ipairs(weldedParts) do
WeldRemote:FireServer(target, weldedPart, false)
end
end
end
end
function updateActionUI()
if isMobile then return end
local isHovering = target and not grabbedOBJ
local isDragging = grabbedOBJ ~= nil
local function setActionVisibility(name, visible, key, pad, order)
if visible and not activeActions[name] then
ActionManager.bindAction(name, actionHandler, key, pad, order)
activeActions[name] = true
elseif not visible and activeActions[name] then
ActionManager.unbindAction(name)
activeActions[name] = nil
end
end
setActionVisibility("Drag", isHovering, Enum.UserInputType.MouseButton1, Enum.KeyCode.ButtonA, 1)
setActionVisibility("Drop", isDragging, Enum.UserInputType.MouseButton1, Enum.KeyCode.ButtonA, 1)
setActionVisibility("Rotate", isDragging, Enum.KeyCode.R, Enum.KeyCode.ButtonR1, 2)
setActionVisibility("Change Axis", isDragging, Enum.KeyCode.T, Enum.KeyCode.ButtonL1, 3)
local showWeldActions = isDragging and isWeldable(grabbedOBJ)
if showWeldActions then
local isWelded = #getWeldedParts(grabbedOBJ) > 0
local canWeld = not isWelded and getClosestWeldablePart(grabbedOBJ) ~= nil
setActionVisibility("Unweld", isWelded, Enum.KeyCode.Z, Enum.KeyCode.ButtonX, 4)
setActionVisibility("Weld", canWeld, Enum.KeyCode.Z, Enum.KeyCode.ButtonX, 4)
else
setActionVisibility("Weld", false, nil, nil, 4)
setActionVisibility("Unweld", false, nil, nil, 4)
end
end
function updateWeldButtons()
if not (isMobile and WeldButton) then return end
if grabbedOBJ and isWeldable(grabbedOBJ) then
local weldedParts = getWeldedParts(grabbedOBJ)
if #weldedParts > 0 then
WeldButton.Visible = true
WeldButton.Text = "Unweld"
elseif getClosestWeldablePart(grabbedOBJ) then
WeldButton.Visible = true
WeldButton.Text = "Weld"
else
WeldButton.Visible = false
end
else
WeldButton.Visible = false
end
end
function actionHandler(actionName, inputState, inputObject)
if actionName == "Drag" and inputState == Enum.UserInputState.Begin then
grabAction()
elseif actionName == "Drop" and inputState == Enum.UserInputState.End then
dropAction()
elseif actionName == "Rotate" then
rotateAction(inputState == Enum.UserInputState.Begin)
elseif actionName == "Change Axis" and inputState == Enum.UserInputState.Begin then
changeAxisAction()
elseif (actionName == "Weld" or actionName == "Unweld") and inputState == Enum.UserInputState.Begin then
weldAction()
end
task.wait()
updateActionUI()
end
if isMobile then
local function onInputBegan(input, gameProcessedEvent)
if gameProcessedEvent then isPointerOverGui = true end
if input.UserInputType == Enum.UserInputType.Touch then
currentTouchPosition = input.Position
end
end
local function onInputEnded(input)
isPointerOverGui = false
if input.UserInputType == Enum.UserInputType.Touch then
currentTouchPosition = nil
end
end
local function onInputChanged(input)
if input.UserInputType == Enum.UserInputType.Touch and not isPointerOverGui then
currentTouchPosition = input.Position
end
end
UserInputService.InputBegan:Connect(onInputBegan)
UserInputService.InputEnded:Connect(onInputEnded)
UserInputService.InputChanged:Connect(onInputChanged)
end
RunService.Heartbeat:Connect(function(deltaTime)
if grabbedOBJ then
local dragAttachment = checkAttachment(grabbedOBJ)
script.AlignOrientation.Attachment0 = dragAttachment
script.AlignPosition.Attachment0 = dragAttachment
local targetCF = camera.CFrame * CFrame.new(0, 0, -distance)
if isRotating then
local rot = math.rad(rotationSpeed * deltaTime)
if currentAxis == 1 then
accumulatedRotation *= CFrame.Angles(rot, 0, 0)
elseif currentAxis == 2 then
accumulatedRotation *= CFrame.Angles(0, rot, 0)
else
accumulatedRotation *= CFrame.Angles(0, 0, rot)
end
end
dragTarg.WorldCFrame = targetCF * accumulatedRotation
HighlightObj(grabbedOBJ, false)
if not isMobile then
updateActionUI()
else
updateWeldButtons()
end
else
if isPointerOverGui then return end
local inputPosition = UserInputService:GetMouseLocation()
if not inputPosition then return end
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
raycastParams.FilterDescendantsInstances = {plr.Character}
local head = plr.Character and plr.Character:FindFirstChild("Head")
local isFirstPerson = head and (camera.CFrame.Position - head.Position).Magnitude < 1 or false
local result: RaycastResult?
local rayOrigin: Vector3
if isFirstPerson and not isMobile then
rayOrigin = camera.CFrame.Position
result = workspace:Raycast(rayOrigin, camera.CFrame.LookVector * maxDistance, raycastParams)
else
local currentInputPos = isMobile and currentTouchPosition or inputPosition
local ray = camera:ScreenPointToRay(currentInputPos.X, currentInputPos.Y)
rayOrigin = ray.Origin
result = workspace:Raycast(rayOrigin, ray.Direction * maxDistance, raycastParams)
end
local newTarget = result and result.Instance:HasTag("Draggable") and result.Instance or nil
if newTarget and newTarget == recentlyDroppedPart then
if os.clock() - recentlyDroppedTimestamp < 0.5 then
newTarget = nil
else
recentlyDroppedPart = nil
end
end
if newTarget ~= target then
target = newTarget
if target and result then
distance = (rayOrigin - result.Position).Magnitude
end
HighlightObj(target, target ~= nil)
updateActionUI()
if isMobile and MainFrame then
MainFrame.Visible = (target ~= nil)
if target then
DragButton.Visible = true
DropButton.Visible = false
RotateButton.Visible = false
ChangeAxisButton.Visible = false
updateWeldButtons()
end
end
end
end
end)
if not isMobile then
updateActionUI()
else
if DragButton and DropButton then
DragButton.MouseButton1Click:Connect(function()
if target and not grabbedOBJ then
if DragFunction:InvokeServer(target, true) then
grabbedOBJ = target
grabbedOBJ.CollisionGroup = "DragCollision"
accumulatedRotation = CFrame.new()
distance = (camera.CFrame.Position - target.Position).Magnitude
target = nil
MainFrame.Visible = true
DragButton.Visible = false
DropButton.Visible = true
RotateButton.Visible = true
ChangeAxisButton.Visible = true
updateWeldButtons()
end
end
end)
DropButton.MouseButton1Click:Connect(function()
if grabbedOBJ then
dropObj()
MainFrame.Visible = false
updateActionUI()
end
end)
if RotateButton then
RotateButton.MouseButton1Down:Connect(function() rotateAction(true) end)
RotateButton.InputEnded:Connect(function() rotateAction(false) end)
end
if ChangeAxisButton then
ChangeAxisButton.MouseButton1Click:Connect(function()
changeAxisAction()
ChangeAxisButton.Text = "Axis: " .. axisNames[currentAxis]
end)
end
if WeldButton then
WeldButton.MouseButton1Click:Connect(function()
local wasHoldingObject = grabbedOBJ
weldAction()
if wasHoldingObject and not grabbedOBJ then
MainFrame.Visible = false
end
end)
end
end
end
Server Code
-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- References
local DragFunction = ReplicatedStorage.DragFunction
local WeldRemote = ReplicatedStorage.Weld
DragFunction.OnServerInvoke = function(plr, obj, requestPickUp)
print("CAUGHT")
if not obj or not obj.Parent then return end
print("CAUGHT")
-- attempting to pickup
if requestPickUp and not obj:GetAttribute("DraggedBy") then
obj:SetAttribute("DraggedBy", plr.UserId)
obj:SetNetworkOwner(plr)
print("Picked")
return true
-- attempting to drop
elseif not requestPickUp and obj:GetAttribute("DraggedBy") == plr.UserId then
obj:SetAttribute("DraggedBy", nil)
obj:SetNetworkOwner(nil)
print("Dropped")
return true
end
end
WeldRemote.OnServerEvent:Connect(function(player, part1, part2, shouldWeld)
if not part1 or not part2 then return end
local actualPart1 = getPrimaryPart(part1) or part1
local actualPart2 = getPrimaryPart(part2) or part2
-- Check Weldable values
if not (hasValue(part1, "Weldable") and hasValue(part2, "Weldable")) then
return
end
-- Only allow weld/unweld if the player is holding the part (using attributes instead of table)
if actualPart1:GetAttribute("DraggedBy") ~= player.UserId then return end
if shouldWeld then
if not isWelded(actualPart1, actualPart2) then
local weld = Instance.new("WeldConstraint")
weld.Part0 = actualPart1
weld.Part1 = actualPart2
weld.Parent = actualPart1
print("it's welded")
end
else
-- Remove existing welds between the two parts
for _, constraint in ipairs(actualPart1:GetChildren()) do
if constraint:IsA("WeldConstraint") and
(constraint.Part0 == actualPart2 or constraint.Part1 == actualPart2) then
constraint:Destroy()
end
end
for _, constraint in ipairs(actualPart2:GetChildren()) do
if constraint:IsA("WeldConstraint") and
(constraint.Part0 == actualPart1 or constraint.Part1 == actualPart1) then
constraint:Destroy()
end
end
print("it's unwelded")
end
end)
function getPrimaryPart(instance)
if instance:IsA("Model") then
return instance.PrimaryPart
end
return instance
end
function isWelded(part1, part2)
for _, constraint in ipairs(part1:GetChildren()) do
if constraint:IsA("WeldConstraint") and
(constraint.Part0 == part2 or constraint.Part1 == part2) then
return true
end
end
return false
end
function hasValue(instance, valueName)
while instance do
if instance:FindFirstChild(valueName) then
return true
end
instance = instance.Parent
end
return false
end