local PathfindingService = game:GetService("PathfindingService") local Players = game:GetService("Players") local player = Players.LocalPlayer local function getCharacter() local character = player.Character if not character then return end local humanoid = character:FindFirstChildOfClass("Humanoid") local rootPart = character:FindFirstChild("HumanoidRootPart") if not humanoid or not rootPart then return end return character, humanoid, rootPart end local stuckState = 0 local lastJumpTime = 0 local JUMP_COOLDOWN = 0.8 local lastDirection = Vector3.new(1, 0, 0) local NavConfig = { Active = true, Radius = 200, WaypointVisuals = true, StoppingDistance = 4, MaxStuckTime = 1.2 } local PLAYER_JUMP_HEIGHT = 7 local PLAYER_WIDTH = 4 local camera = workspace.CurrentCamera local activeLines = {} local function clearAllMarkers() for _, l in pairs(activeLines) do if l then l:Destroy() end end activeLines = {} end local function removeLine(i) if activeLines[i] then activeLines[i]:Destroy() activeLines[i] = nil end end local function drawFullVisualPath(points) clearAllMarkers() if not NavConfig.WaypointVisuals then return end for i = 1, #points - 1 do local a = points[i].Position local b = points[i + 1].Position local dist = (b - a).Magnitude local part = Instance.new("Part") part.Anchored = true part.CanCollide = false part.Material = Enum.Material.Neon part.Color = Color3.fromRGB(255, 255, 0) part.Size = Vector3.new(0.2, 0.2, dist) part.CFrame = CFrame.lookAt(a, b) * CFrame.new(0, 0, -dist / 2) part.Parent = workspace table.insert(activeLines, part) end end local function lookAtCrumb(targetPos, speed) local _, _, rootPart = getCharacter() if not rootPart then return end speed = speed or 25 local camPos = camera.CFrame.Position local dir = targetPos - camPos dir = Vector3.new(dir.X, 0, dir.Z) if dir.Magnitude < 0.001 then return end dir = dir.Unit local targetCF = CFrame.lookAt(camPos, camPos + dir) camera.CFrame = camera.CFrame:Lerp(targetCF, 1 / speed) end local function forceJump(humanoid) local now = os.clock() if now - lastJumpTime < JUMP_COOLDOWN then return end humanoid.Jump = true lastJumpTime = now end local function generateCrumbs(waypoints) local crumbs = {} for i = 1, #waypoints - 1 do table.insert(crumbs, {Position = waypoints[i].Position}) table.insert(crumbs, {Position = waypoints[i + 1].Position}) end table.insert(crumbs, {Position = waypoints[#waypoints].Position}) return crumbs end local function hasTouchDamage(part) local name = part.Name:lower() if name:find("kill") then return true end if name:find("lava") then return true end if name:find("damage") then return true end if part:FindFirstChild("Damage") then return true end return false end local function isPositionDanger(pos) local boxSize = Vector3.new(6, 6, 6) local parts = workspace:GetPartBoundsInBox(CFrame.new(pos), boxSize) for _, p in ipairs(parts) do if p:GetAttribute("Hazard") == true then return true end if hasTouchDamage(p) then return true end end return false end local function buildDestination(mode, baseDir, rootPart) if mode == 0 then return rootPart.Position + Vector3.new( math.random(-NavConfig.Radius, NavConfig.Radius), 0, math.random(-NavConfig.Radius, NavConfig.Radius) ) elseif mode == 1 then local offset = baseDir.Unit * math.random(40, 120) return rootPart.Position + offset + Vector3.new(math.random(-20, 20), 0, math.random(-20, 20)) else return rootPart.Position + Vector3.new( math.random(-NavConfig.Radius, NavConfig.Radius), 0, math.random(-NavConfig.Radius, NavConfig.Radius) ) end end local function followCrumbs(crumbs) local index = 1 local stuckTime = 0 while index <= #crumbs do if not NavConfig.Active then return false end local character, humanoid, rootPart = getCharacter() if not character or not humanoid or not rootPart then task.wait(0.1) return false end local crumb = crumbs[index] local nextLook = crumbs[math.min(index, #crumbs)] lookAtCrumb(nextLook.Position, 5) local target = crumb.Position local pos = rootPart.Position local delta = target - pos local planar = Vector3.new(delta.X, 0, delta.Z) if planar.Magnitude < NavConfig.StoppingDistance then local nextCrumb = crumbs[index + 1] if nextCrumb then local deltaY = nextCrumb.Position.Y - pos.Y if deltaY > 2 then forceJump(humanoid) end end removeLine(index) index += 1 stuckTime = 0 continue end local dir = planar.Magnitude > 0 and planar.Unit or Vector3.zero humanoid:MoveTo(pos + dir * 8) if (pos - rootPart.Position).Magnitude > 0.15 then stuckTime = 0 else stuckTime += 0.05 end if stuckTime > NavConfig.MaxStuckTime then return false end task.wait() end return true end player.CharacterAdded:Connect(function() clearAllMarkers() stuckState = 0 lastDirection = Vector3.new(1, 0, 0) end) task.spawn(function() print("NavBot SAFE VERSION") while true do if not NavConfig.Active then task.wait(1) continue end local character, humanoid, rootPart = getCharacter() if not character or not humanoid or not rootPart then task.wait(0.2) continue end local mode = stuckState % 3 local destination = buildDestination(mode, lastDirection, rootPart) local path = PathfindingService:CreatePath({ AgentRadius = 3, AgentHeight = 5, AgentCanJump = true, WaypointSpacing = 6 }) local success = pcall(function() path:ComputeAsync(rootPart.Position, destination) end) if success and path.Status == Enum.PathStatus.Success then local waypoints = path:GetWaypoints() local crumbs = generateCrumbs(waypoints) drawFullVisualPath(crumbs) local ok = followCrumbs(crumbs) if not ok then stuckState += 1 lastDirection = (destination - rootPart.Position) clearAllMarkers() task.wait(0.1) else stuckState = 0 clearAllMarkers() task.wait(0.2) end else stuckState += 1 clearAllMarkers() task.wait(0.3) end end end)