- scripts
- DragDetector probe v2
Source
--!nonstrict
--[[=========================================================================
DragDetector probe
Finds a draggable part and works out WHICH method actually moves it, if
any. Nothing is swallowed: every write reports whether it took, and every
method reports whether the part physically moved afterwards.
Methods tried, in order:
1. write DragFrame directly (no active drag session)
2. same, after forcing the detector's settings
3. RestartDrag() then write DragFrame
4. simulated mouse drag via VirtualInputManager (a real drag session)
It also dumps the detector's own settings first, because RunLocally = true
means the drag is client-only by the game's own choice and nothing here
will ever replicate.
=========================================================================]]
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local LocalPlayer = Players.LocalPlayer
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 = "DragProbe"
gui.ResetOnSpawn = false
gui.IgnoreGuiInset = true
gui.Parent = guiHost()
local frame = Instance.new("Frame")
frame.Size = UDim2.new(0, 520, 0, 320)
frame.Position = UDim2.new(0.5, -260, 0, 40)
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.Text = "probing..."
text.Parent = gui and frame
local lines = {}
local function log(line)
lines[#lines + 1] = line
text.Text = table.concat(lines, "\n")
print("[dragprobe] " .. line)
end
local function findDetector()
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 return inst, node end
node = node.Parent
end
end
end
return nil
end
-- try a write and say plainly whether it took
local function tryWrite(inst, prop, value)
local ok, err = pcall(function() inst[prop] = value end)
if not ok then
return false, tostring(err)
end
local got
pcall(function() got = inst[prop] end)
return true, tostring(got)
end
local function moved(part, from)
return (part.Position - from).Magnitude
end
task.spawn(function()
log("== DragDetector probe ==")
local det, part = findDetector()
if not det then
log("no DragDetector anywhere in workspace.")
log("This game has no draggable parts, so the Drag tab has nothing")
log("to act on -- that is the whole explanation.")
return
end
log("found: " .. det:GetFullName())
log(" part: " .. part:GetFullName())
-- 1. what does the game itself say about this detector?
local function readProp(name)
local ok, v = pcall(function() return det[name] end)
return ok and tostring(v) or "n/a"
end
log(string.format(" Enabled=%s RunLocally=%s Response=%s",
readProp("Enabled"), readProp("RunLocally"), readProp("ResponseStyle")))
log(string.format(" DragStyle=%s Permission=%s MaxDist=%s",
readProp("DragStyle"), readProp("PermissionPolicy"),
readProp("MaxActivationDistance")))
if readProp("RunLocally") == "true" then
log("!! RunLocally is TRUE -- this game made the drag client-only.")
log(" Nothing any script does here will replicate.")
end
local box = Instance.new("SelectionBox")
box.Adornee = part
box.Color3 = Color3.fromRGB(255, 190, 80)
box.Transparency = 0.5
box.LineThickness = 0.05
box.Parent = gui
local function attempt(name, fn)
local from = part.Position
local ok, err = pcall(fn)
for _ = 1, 12 do RunService.Heartbeat:Wait() end
local d = moved(part, from)
log(string.format("%s -> %s, part moved %.2f studs",
name, ok and "write ok" or ("ERR " .. tostring(err)), d))
return d
end
-- 2. plain DragFrame write, exactly what the hub was doing
local best = attempt("1. DragFrame write", function()
det.DragFrame = det.DragFrame + Vector3.new(0, 25, 0)
end)
-- 3. force the settings first
local okE, msgE = tryWrite(det, "Enabled", true)
log(" set Enabled -> " .. (okE and msgE or msgE))
local okR, msgR = tryWrite(det, "RunLocally", false)
log(" set RunLocally -> " .. (okR and msgR or msgR))
local okS = tryWrite(det, "ResponseStyle", Enum.DragDetectorResponseStyle.Geometric)
log(" set ResponseStyle -> " .. tostring(okS))
pcall(function() det.MaxActivationDistance = 1e6 end)
best = math.max(best, attempt("2. DragFrame after forcing settings", function()
det.DragFrame = det.DragFrame + Vector3.new(0, 25, 0)
end))
-- 4. RestartDrag first, in case a live drag session is required
best = math.max(best, attempt("3. RestartDrag + DragFrame", function()
det:RestartDrag()
det.DragFrame = det.DragFrame + Vector3.new(0, 25, 0)
end))
-- 5. an actual simulated drag, which is what the engine really listens for
local vimOk = pcall(function() return game:GetService("VirtualInputManager") end)
log("VirtualInputManager available: " .. tostring(vimOk))
if vimOk then
best = math.max(best, attempt("4. simulated mouse drag", function()
local VIM = game:GetService("VirtualInputManager")
local cam = workspace.CurrentCamera
local sp, onScreen = cam:WorldToViewportPoint(part.Position)
if not onScreen then error("part is off-screen; look at it and re-run") end
VIM:SendMouseButtonEvent(sp.X, sp.Y, 0, true, game, 0)
for i = 1, 10 do
VIM:SendMouseMoveEvent(sp.X, sp.Y - i * 6, game)
RunService.Heartbeat:Wait()
end
VIM:SendMouseButtonEvent(sp.X, sp.Y - 60, 0, false, game, 0)
end))
end
log("")
if best < 0.5 then
log("VERDICT: nothing moved it.")
log("Either the game blocks it (PermissionPolicy), or a drag only")
log("works from real input while you are looking at the part.")
else
log(string.format("VERDICT: something worked -- best movement %.2f studs.", best))
log("Tell me which numbered method moved it and I will make the")
log("hub's Drag section use that one.")
end
task.delay(15, function()
box:Destroy()
gui:Destroy()
end)
end)