I've tried scripting a grab tool on my own. Seems to work when I tried testing in the Studio, doesn't work at all (bar the arm-moving part, which I copied from the Night At The Museum flashlight.)
Here are the scripts.
Server:
wait(0.4) local Tool = script.Parent local Handle = Tool:WaitForChild("Handle") local Remote = Tool:FindFirstChild("Remote") local Weld local Motor local MotorPart0 local MotorPart1 local GripParts = {} local CertainPartsToGrab = {"Part", "Potato"} --Certin name of parts TO GRAB local GrabListOn = false --Is this list functional? If true, then grabs ONLY parts with names in this bracket and nothing else local CertainPartsToIgnore = {"Baseplate", "Capitalism"} --Certin name of parts TO IGNORE local IgnoreListOn = true --Is this list functional? If true, then grabs EVERYTHING ELSE except parts in this bracket local PartRange = 5 --How far away from the torso can the part be grabbed (in studs) local GrabbedPart print ("ok") function getPlayer() return game:GetService("Players"):GetPlayerFromCharacter(Tool.Parent) end function setPointDirection(position) local char = Tool.Parent if not char then return end if not Weld then Motor = char.Torso["Right Shoulder"]:Clone() MotorPart0 = char.Torso MotorPart1 = char["Right Arm"] Weld = Instance.new("Weld") Weld.Part0 = char.Torso Weld.Part1 = char["Right Arm"] Weld.C0 = CFrame.new(1, 1, 0) Weld.Parent = Weld.Part0 end local jointPosition = Weld.Part0.CFrame:toWorldSpace(CFrame.new(1.5, 0.5, 0)) local cframe = CFrame.new(jointPosition.p, position) * CFrame.Angles(math.pi/2, 0, 0) * CFrame.new(0, -0.5, 0) Weld.C0 = Weld.Part0.CFrame:toObjectSpace(cframe) end function MouseDown(Mouse, Character, Torso, RArm) print("MouseDown server fire") local GrabListPass = false local IgnoreListPass = false local RayBeam = Ray.new(Torso.CFrame.p, (Mouse.Hit.p - Torso.CFrame.p).unit * 300) local RayHitPart, RayHitPos = game.Workspace:FindPartOnRay(RayBeam, Character, false, false) local Distance = (Torso.CFrame.p - RayHitPos).magnitude if GrabListOn == true then for _, Name in pairs (CertainPartsToGrab) do if tostring(Name) == RayHitPart.Name then GrabListPass = true break elseif tostring(Name) ~= RayHitPart.Name then GrabListPass = false end end elseif GrabListOn == false then GrabListPass = true end if IgnoreListOn == true then for _, Name in pairs (CertainPartsToIgnore) do if tostring(Name) ~= RayHitPart.Name then IgnoreListPass = true elseif tostring(Name) == RayHitPart.Name then IgnoreListPass = false break end end elseif IgnoreListOn == false then IgnoreListPass = true end if GrabListPass == true and IgnoreListPass == true then if Distance <= PartRange and Mouse.Target ~= nil then GrabbedPart = Mouse.Target local PosPartR = Instance.new("Part", game.Workspace) PosPartR.CFrame = CFrame.new(RayHitPos) PosPartR.Anchored = false PosPartR.CanCollide = false PosPartR.Size = Vector3.new(0.2, 0.2, 0.2) PosPartR.Transparency = 1 local PartWeld = Instance.new("Weld", PosPartR) PartWeld.Part0 = PosPartR PartWeld.Part1 = RayHitPart table.insert(GripParts, PosPartR) local RPartAttach = Instance.new("Attachment", PosPartR) RPartAttach.Position = Vector3.new(0, 0, 0) RPartAttach.Name = "RightPartAttachment" local RArmAttach = Instance.new("Attachment", RArm) RArmAttach.Name = "RightArmAttachment" RArmAttach.Position = Vector3.new(0, -1, 0) local RBallCons = Instance.new("BallSocketConstraint", PosPartR) RBallCons.Name = "RGripCons" RBallCons.Attachment0 = RPartAttach RBallCons.Attachment1 = RArmAttach GrabbedPart.CanCollide = false end end end function MouseUp(RArm) print("MouseUp server fire") for _, Part in pairs (GripParts) do Part:Destroy() end for _, Part in pairs (RArm:GetChildren()) do if Part.Name == "RightArmAttachment" then Part:Destroy() end end if GrabbedPart then GrabbedPart.CanCollide = true GrabbedPart = nil end end function onRemote(player, func, ...) if player ~= getPlayer() then return end if func == "UpdateDirection" then setPointDirection(...) end if func == "MouseDown" then MouseDown(...) print("MouseDown remote fire") end if func == "MouseUp" then MouseUp(...) print("MouseUp remote fire") end end function onEquipped() Handle.Transparency = 1 end function onUnequipped() if Weld then Weld:Destroy() Weld = nil end if Motor then Motor.Part0 = MotorPart0 Motor.Part1 = MotorPart1 Motor.Parent = MotorPart0 Motor = nil end Handle.Transparency = 0 for _, Part in pairs (GripParts) do Part:Destroy() end local RArm = getPlayer().Character:FindFirstChild("Right Arm") for _, Part in pairs (RArm:GetChildren()) do if Part.Name == "RightArmAttachment" then Part:Destroy() end end end Remote.OnServerEvent:connect(onRemote) Tool.Equipped:connect(onEquipped) Tool.Unequipped:connect(onUnequipped)
Local:
local Player = game:GetService("Players").LocalPlayer local Mouse = Player:GetMouse() local Tool = script.Parent local Remote = Tool:WaitForChild("Remote") function onMouseMove() Player = game:GetService("Players").LocalPlayer Mouse = Player:GetMouse() Remote:FireServer("UpdateDirection", Mouse.Hit.p) end function onMouseDown() Player = game:GetService("Players").LocalPlayer Mouse = Player:GetMouse() local Character = Player.Character local Torso = Character:FindFirstChild("Torso") local RArm = Character:FindFirstChild("Right Arm") Remote:FireServer("MouseDown", Mouse, Character, Torso, RArm) print("MouseDown fire") end function onMouseUp() Player = game:GetService("Players").LocalPlayer local Character = Player.Character local RArm = Character:FindFirstChild("Right Arm") Remote:FireServer("MouseUp", RArm) print("MouseUp fire") end Mouse.Move:connect(onMouseMove) Mouse.Button1Down:connect(onMouseDown) Mouse.Button1Up:connect(onMouseUp) game:GetService("RunService").Heartbeat:connect(onMouseMove)
As I've mentioned before, the tool worked flawlessly in the local Studio test. It's broken when used in an actual game server.