My AC Server: Discord
This method detects when a player scrolls the mouse wheel but the camera zoom does not change. If the cursor is not over a scrollable GUI element, the behavior is flagged as suspicious.
Source:
local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local GuiService = game:GetService("GuiService")
local RunService = game:GetService("RunService")
local LocalPlayer = Players.LocalPlayer
local Camera = workspace.CurrentCamera
local scrollWindowStart = 0
local scrollCount = 0
local function findInteractiveGui(gui)
while gui do
if (gui:IsA("ScrollingFrame") or gui:IsA("TextBox") or gui:IsA("TextButton")) and gui.Visible then
return gui
end
gui = gui.Parent
end
end
local function isMouseOverSurfaceGui()
local mouse = UserInputService:GetMouseLocation() - GuiService:GetGuiInset()
local ray = Camera:ScreenPointToRay(mouse.X, mouse.Y)
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Blacklist
local character = LocalPlayer.Character
if character then
params.FilterDescendantsInstances = {character}
end
local result = workspace:Raycast(ray.Origin, ray.Direction * 1000, params)
if not result then
return false
end
local part = result.Instance
for _, surface in ipairs(part:GetDescendants()) do
if surface:IsA("SurfaceGui") and surface.Enabled then
for _, obj in ipairs(surface:GetDescendants()) do
if obj:IsA("ScrollingFrame") and obj.Visible then
return true, obj
end
end
end
end
return false
end
local function isMouseInUI()
local mouse = UserInputService:GetMouseLocation() - GuiService:GetGuiInset()
local playerGui = LocalPlayer:WaitForChild("PlayerGui")
for _, gui in ipairs(playerGui:GetGuiObjectsAtPosition(mouse.X, mouse.Y)) do
local found = findInteractiveGui(gui)
if found then
return true, found
end
end
return isMouseOverSurfaceGui()
end
local function getCameraDistance()
local character = LocalPlayer.Character
if not character then return 0 end
local head = character:FindFirstChild("Head")
if not head then return 0 end
return (Camera.CFrame.Position - head.Position).Magnitude
end
local function isCameraBlocked()
local character = LocalPlayer.Character
if not character then return false end
local head = character:FindFirstChild("Head")
if not head then return false end
local params = RaycastParams.new()
params.FilterDescendantsInstances = {character}
params.FilterType = Enum.RaycastFilterType.Blacklist
local direction = Camera.CFrame.Position - head.Position
return workspace:Raycast(head.Position, direction, params) ~= nil
end
local function isShiftLock()
return UserInputService.MouseBehavior == Enum.MouseBehavior.LockCenter
end
local function onMouseWheel(input)
if input.UserInputType ~= Enum.UserInputType.MouseWheel then
return
end
if isMouseInUI() or isShiftLock() or isCameraBlocked() then
return
end
local before = getCameraDistance()
RunService.RenderStepped:Wait()
local maxDelta = 0
local totalDelta = 0
for _ = 1, 5 do
RunService.RenderStepped:Wait()
local after = getCameraDistance()
local delta = after - before
totalDelta += delta
maxDelta = math.max(maxDelta, math.abs(delta))
before = after
end
local minZoom = LocalPlayer.CameraMinZoomDistance
local maxZoom = LocalPlayer.CameraMaxZoomDistance
local distance = getCameraDistance()
if distance <= minZoom + 0.2 or distance >= maxZoom - 0.2 then
return
end
local threshold = math.max(0.02, distance * 0.003)
if maxDelta < threshold and math.abs(totalDelta) < threshold then
local now = tick()
if now - scrollWindowStart > 0.5 then
scrollWindowStart = now
scrollCount = 0
end
scrollCount += 1
if scrollCount >= 5 then
warn("detected!")
end
end
end
UserInputService.InputChanged:Connect(onMouseWheel)
Showcase: Watch Roblox-2026-05-19T18_04_40.682Z | Streamable
Todo:
Check Roblox Menu Openning: It will disable all input connection so u dont have to
Check Console Openning
Check Roblox Modals (PromptPurchase, PromptGameInvite,…)
Check MicroProfiler, Performance Stats (maybe whitelist topbar? dont detect if mouse pos is in topbar)
Custom ChatFrame & PlayerList Frame to put it in PlayerGui