-- AUTO WALLHOP, By - @xx4naxx on YT -- Services local Players = game:GetService("Players") local RunService = game:GetService("RunService") local Workspace = game:GetService("Workspace") -- Allows Use with other scripts, and advanced features like `Randomise flick angle(min-max)` -- Global config so u can change this later on without Re-Executing, copy paste if necesary getgenv().Wallhop_Config = { wallCheckDistance = 2.5, -- ray length (studs) jumpCooldown = 0.3, -- seconds between hops, usualy should be larger than flick duration flickAngle = 60, -- degerees flickDuration = 0.25, -- duration of hop sequence or smth autoWallHop = true, requireVertical = true, -- self explanatory -- seam detection sampleBand = 1.2, -- up/down step sample rate sampleCount = 9, -- vertical samples per direction seamTolerance = 0.6, -- max distance of intercestion from legs (studs) directions = 8, -- horizontal ray directions } local player = Players.LocalPlayer -- States local character, humanoid, hrp local lastJumpTime = 0 local flick = { active = false, t = 0, baseYaw = 0 } -- Raycasts local rayParams = RaycastParams.new() do local ok, ft = pcall(function() return Enum.RaycastFilterType.Exclude end) rayParams.FilterType = ok and ft or Enum.RaycastFilterType.Blacklist rayParams.IgnoreWater = true end -- Precompute horizontal ray directions (full circle) local RAY_DIRS = {} for i = 0, getgenv().Wallhop_Config.directions - 1 do local a = (i / getgenv().Wallhop_Config.directions) * math.pi * 2 RAY_DIRS[i + 1] = Vector3.new(math.cos(a), 0, math.sin(a)) end -- Math funcs local function normalizeAngle(a) return (a + math.pi) % (2 * math.pi) - math.pi end local function getYaw(cf) local l = cf.LookVector return math.atan2(-l.X, -l.Z) end local function smoothstep(s) s = math.clamp(s, 0, 1) return s * s * (3 - 2 * s) end local function setYawAbsolute(yaw) local cf, pos = hrp.CFrame, hrp.CFrame.Position local delta = normalizeAngle(yaw - getYaw(cf)) if math.abs(delta) < 1e-4 then return end local lv, av = hrp.AssemblyLinearVelocity, hrp.AssemblyAngularVelocity hrp.CFrame = CFrame.new(pos) * CFrame.Angles(0, delta, 0) * (cf - pos) hrp.AssemblyLinearVelocity = lv hrp.AssemblyAngularVelocity = av end -- Y lev of char's feet local function getFeetY() return hrp.Position.Y - hrp.Size.Y * 0.5 - (humanoid.HipHeight or 0) end --[[ SEAM DETECTION: For each horizontal direction, sample the wall at several Y heights around the legs. A seam is detected when two ADJACENT samples (with no gap between them) hit DIFFERENT parts, and the seam is within seamTolerance of the feet. ]] local function isWallHit(result) if not result or not result.Instance or not result.Instance.CanCollide then return false end if getgenv().Wallhop_Config.requireVertical and math.abs(result.Normal.Y) >= 0.35 then return false end return true end local function findSeam() local origin = hrp.Position local feetY = getFeetY() local halfBand = getgenv().Wallhop_Config.sampleBand local n = getgenv().Wallhop_Config.sampleCount local step = (halfBand * 2) / (n - 1) for _, dir in ipairs(RAY_DIRS) do local prevPart, prevY = nil, nil for k = 1, n do local y = feetY - halfBand + step * (k - 1) local o = Vector3.new(origin.X, y, origin.Z) local r = Workspace:Raycast(o, dir * getgenv().Wallhop_Config.wallCheckDistance, rayParams) if isWallHit(r) then local part = r.Instance if prevPart and part ~= prevPart then -- seam detec local seamY = (prevY + y) * 0.5 if math.abs(seamY - feetY) <= getgenv().Wallhop_Config.seamTolerance then return true end end prevPart = part prevY = y else -- unless intersection we hop, we didnt get intersection prevPart, prevY = nil, nil end end end return false end -- Frames local function startFlick() if flick.active then return end flick.active = true flick.t = 0 flick.baseYaw = getYaw(hrp.CFrame) humanoid.AutoRotate = false end local function updateFlick(dt) if not flick.active then return end flick.t = flick.t + dt local a = math.clamp(flick.t / getgenv().Wallhop_Config.flickDuration, 0, 1) local angle = math.rad(getgenv().Wallhop_Config.flickAngle) local offset if a < 1/3 then offset = -angle * smoothstep(a * 3) elseif a < 2/3 then offset = -angle + (2 * angle) * smoothstep((a - 1/3) * 3) else offset = angle - angle * smoothstep((a - 2/3) * 3) end setYawAbsolute(flick.baseYaw + offset) if a >= 1 then flick.active = false setYawAbsolute(flick.baseYaw) humanoid.AutoRotate = true end end -- Char binder local function onCharacter(char) character = char humanoid = char:WaitForChild("Humanoid") hrp = char:WaitForChild("HumanoidRootPart") rayParams.FilterDescendantsInstances = { char } flick.active = false lastJumpTime = 0 end player.CharacterAdded:Connect(onCharacter) if player.Character then onCharacter(player.Character) end -- Main Loop RunService.RenderStepped:Connect(function(dt) if not hrp or not humanoid or humanoid.Health <= 0 then return end updateFlick(dt) if not getgenv().Wallhop_Config.autoWallHop then return end if flick.active then return end if os.clock() - lastJumpTime < getgenv().Wallhop_Config.jumpCooldown then return end -- dont want to hop when yr on the ground do you? if humanoid.FloorMaterial ~= Enum.Material.Air then return end -- Anti-laddr + swim local state = humanoid:GetState() if state == Enum.HumanoidStateType.Climbing or state == Enum.HumanoidStateType.Swimming then return end --hop on intersections if not findSeam() then return end lastJumpTime = os.clock() startFlick() humanoid:ChangeState(Enum.HumanoidStateType.Jumping) end)