--!nonstrict --[[========================================================================= DragDetector probe v3 v1 measured movement with no control, so gravity read as success. v2 added the control but still only measured movement, which cannot tell "our input never arrived" apart from "the drag was refused". v3 instruments the drag itself. The detector fires DragStart / DragContinue / DragEnd, so we count them. That splits every failure mode apart: DragStart never fires on OUR input, but fires when YOU drag by hand -> our injection is the problem (security, aim, coordinate space) DragStart never fires even when you drag by hand -> this part is not really draggable; nothing to exploit DragStart fires but the part does not move -> the drag is running and being refused or is local-only DragStart fires and the part moves -> it works, and we know exactly which method did it Two things found in the API dump that v1/v2 got wrong: * VirtualInputManager's mouse methods are RobloxScriptSecurity, so a plain script cannot call them -- it depends on the executor. * WorldToViewportPoint excludes the GUI inset. Feeding those coordinates to a mouse event aims ~36px above the part and misses it. The inset has to be added back. =========================================================================]] local Players = game:GetService("Players") local RunService = game:GetService("RunService") local UserInput = game:GetService("UserInputService") local GuiService = game:GetService("GuiService") local LocalPlayer = Players.LocalPlayer local Mouse = LocalPlayer:GetMouse() local function guiHost() if gethui then local ok, host = pcall(gethui) if ok and host then return host end end local ok, core = pcall(game.GetService, game, "CoreGui") if ok and core then return core end return LocalPlayer:WaitForChild("PlayerGui") end local gui = Instance.new("ScreenGui") gui.Name = "DragProbe3" gui.ResetOnSpawn = false gui.IgnoreGuiInset = true gui.Parent = guiHost() local frame = Instance.new("Frame") frame.Size = UDim2.new(0, 580, 0, 400) frame.Position = UDim2.new(0, 20, 0, 60) frame.BackgroundColor3 = Color3.fromRGB(16, 16, 22) frame.BorderSizePixel = 0 frame.Parent = gui Instance.new("UICorner", frame).CornerRadius = UDim.new(0, 8) local text = Instance.new("TextLabel") text.BackgroundTransparency = 1 text.Position = UDim2.new(0, 12, 0, 10) text.Size = UDim2.new(1, -24, 1, -20) text.Font = Enum.Font.Code text.TextSize = 13 text.TextColor3 = Color3.fromRGB(215, 220, 235) text.TextXAlignment = Enum.TextXAlignment.Left text.TextYAlignment = Enum.TextYAlignment.Top text.TextWrapped = true text.Parent = frame local lines = {} local function log(line) lines[#lines + 1] = line if #lines > 25 then table.remove(lines, 1) end text.Text = table.concat(lines, "\n") print("[dragprobe] " .. line) end local function wait(n) for _ = 1, n do RunService.Heartbeat:Wait() end end task.spawn(function() log("== DragDetector probe v3 ==") local det, part for _, inst in ipairs(workspace:GetDescendants()) do if inst:IsA("DragDetector") then local node = inst.Parent for _ = 1, 3 do if not node then break end if node:IsA("BasePart") then det, part = inst, node break end node = node.Parent end end if det then break end end if not det then log("no DragDetector in workspace. Nothing to test.") return end log("part: " .. part:GetFullName()) log(string.format("Anchored=%s RunLocally=%s Policy=%s", tostring(part.Anchored), tostring(det.RunLocally), tostring(det.PermissionPolicy))) -- THE instrumentation: does the engine think a drag is happening? local starts, continues, ends = 0, 0, 0 local who = "?" det.DragStart:Connect(function(player) starts = starts + 1 who = player and player.Name or "nil" end) det.DragContinue:Connect(function() continues = continues + 1 end) det.DragEnd:Connect(function() ends = ends + 1 end) local box = Instance.new("SelectionBox") box.Adornee = part box.Color3 = Color3.fromRGB(120, 220, 255) box.Transparency = 0.6 box.LineThickness = 0.04 box.Parent = gui -- ---------------------------------------------------------------- aim local inset = GuiService:GetGuiInset() log(string.format("GUI inset: %d, %d", inset.X, inset.Y)) local cam = workspace.CurrentCamera local vp, onScreen = cam:WorldToViewportPoint(part.Position) if not onScreen then log("part is OFF SCREEN -- look at it and re-run.") return end log(string.format("part at viewport %d,%d -> screen %d,%d", vp.X, vp.Y, vp.X + inset.X, vp.Y + inset.Y)) -- ---------------------------------------------------------------- vim local VIM local okSvc, err = pcall(function() VIM = game:GetService("VirtualInputManager") end) log("VirtualInputManager: " .. (okSvc and "available" or ("BLOCKED " .. tostring(err)))) local function tryMove(x, y, label) local ok, e = pcall(function() VIM:SendMouseMoveEvent(x, y, game) end) wait(3) local loc = UserInput:GetMouseLocation() local hit = Mouse.Target log(string.format(" %s -> %s | cursor now %d,%d | over: %s", label, ok and "sent" or ("ERR " .. tostring(e)), loc.X, loc.Y, hit and hit.Name or "nothing")) return ok and hit == part end local aimed = false if VIM then log("aim test:") -- the wrong way (what v1/v2 did) and the right way, side by side aimed = tryMove(vp.X, vp.Y, "viewport coords (no inset)") local aimed2 = tryMove(vp.X + inset.X, vp.Y + inset.Y, "screen coords (inset added)") aimed = aimed or aimed2 if aimed2 then vp = { X = vp.X + inset.X, Y = vp.Y + inset.Y } end log(aimed and " -> cursor IS on the part" or " -> cursor is NOT landing on the part") end -- ------------------------------------------------------- injected drag local function report(tag, from) local moved = (part.Position - from).Magnitude log(string.format("%s: starts=%d continue=%d end=%d moved=%.2f by=%s", tag, starts, continues, ends, moved, who)) end if VIM and aimed then starts, continues, ends = 0, 0, 0 local from = part.Position pcall(function() VIM:SendMouseButtonEvent(vp.X, vp.Y, 0, true, game, 0) for i = 1, 20 do VIM:SendMouseMoveEvent(vp.X, vp.Y - i * 18, game) RunService.Heartbeat:Wait() end VIM:SendMouseButtonEvent(vp.X, vp.Y - 360, 0, false, game, 0) end) wait(20) report("injected drag", from) end -- ------------------------------------------------------------ dragframe starts, continues, ends = 0, 0, 0 local from = part.Position pcall(function() det.DragFrame = det.DragFrame + Vector3.new(0, 60, 0) end) wait(25) report("DragFrame write", from) -- --------------------------------------------------------- HUMAN CONTROL log("") log(">> NOW DRAG THE OUTLINED PART WITH YOUR OWN MOUSE <<") log(" you have 8 seconds...") starts, continues, ends = 0, 0, 0 from = part.Position wait(8 * 60) report("YOUR manual drag", from) log("") if starts == 0 then log("VERDICT: even YOUR real mouse never started a drag.") log("This part is not actually draggable for you -- permission policy,") log("distance, or the game disabled it. No script can fix that.") else log("VERDICT: manual dragging DOES work here (" .. starts .. " starts).") log("So the drag system is live and the problem is our injection --") log("tell me the aim-test line and I will fix the coordinates.") end task.delay(25, function() box:Destroy() gui:Destroy() end) end)