{"id":"nsawill1405/pathfinding-plus","name":"pathfinding-plus","scope":"nsawill1405","platform":"roblox","description":"Crowd-coordination pathfinding utilities for Roblox, built on PathfindingService.","version":"0.1.0","latest":"0.1.0","versions":["0.1.0"],"license":"MIT","licenseRating":"safe","licenseCaveats":[],"licenseVerified":true,"dependencies":{},"integrity":"4d74e02a33cdb7064b0157fe0b3e94dbc17e9e0b68c6f590213aa7d93e7a0984","likes":0,"downloads":0,"install":"forest install nsawill1405/pathfinding-plus","url":"https://forest.dev/p/roblox/nsawill1405/pathfinding-plus","files":"https://api.forest.dev/ai/package/roblox/nsawill1405/pathfinding-plus/files","readme":"# Pathfinding Plus\n\n`Pathfinding Plus` is a Wally package for Roblox developers who want a more reliable pathfinding layer than raw `PathfindingService` calls.\n\nIt ships three layers:\n- `Planner` for path computation and normalized results\n- `Navigator` for single-humanoid movement, cancellation, stuck detection, and replans\n- `Coordinator` for shared compute budgeting, staggered replans, and lightweight crowd spacing\n\n## Install\n\nAdd the package to your `wally.toml`:\n\n```toml\n[dependencies]\nPathfindingPlus = \"nsawill1405/pathfinding-plus@0.1.0\"\n```\n\nThen install:\n\n```bash\nwally install\n```\n\nRequire it from your game:\n\n```luau\nlocal ReplicatedStorage = game:GetService(\"ReplicatedStorage\")\nlocal Packages = ReplicatedStorage:WaitForChild(\"Packages\")\n\nlocal PathfindingPlus = require(Packages:WaitForChild(\"PathfindingPlus\"))\n```\n\n## Quick Start\n\n### Single navigator\n\n```luau\nlocal PathfindingPlus = require(game.ReplicatedStorage.Packages.PathfindingPlus)\n\nlocal navigator = PathfindingPlus.Navigator.new(workspace.NPC, {\n\tplannerConfig = {\n\t\tagentParameters = {\n\t\t\tAgentRadius = 2,\n\t\t\tAgentHeight = 5,\n\t\t\tAgentCanJump = true,\n\t\t\tWaypointSpacing = 4,\n\t\t},\n\t},\n\tmaxReplans = 5,\n\tmoveTimeout = 2.5,\n})\n\nnavigator.Failed:Connect(function(_agent, reason)\n\twarn(\"navigation failed\", reason)\nend)\n\nnavigator:MoveTo(workspace.Target)\n```\n\n### Following a moving target\n\n```luau\nlocal navigator = PathfindingPlus.Navigator.new(workspace.NPC, {\n\tmoveTimeout = 3,\n})\n\nnavigator:MoveTo(workspace.MovingTarget, {\n\tfollowMovingGoal = true,\n\tmovingGoalThreshold = 5,\n\tmovingGoalRepathInterval = 0.4,\n})\n```\n\n### Multiple navigators with one coordinator\n\n```luau\nlocal PathfindingPlus = require(game.ReplicatedStorage.Packages.PathfindingPlus)\n\nlocal coordinator = PathfindingPlus.Coordinator.new({\n\tmaxRequestsPerSecond = 12,\n\tperNavigatorCooldown = 0.2,\n})\n\ncoordinator:SetTargetSpacing(workspace.CrowdGoal, 10, 8)\n\nfor _, npc in ipairs(workspace.CrowdNPCs:GetChildren()) do\n\tlocal navigator = PathfindingPlus.Navigator.new(npc, {\n\t\tcoordinator = coordinator,\n\t\tmaxReplans = 6,\n\t})\n\n\tnavigator:MoveTo(workspace.CrowdGoal)\nend\n```\n\n## Public API\n\n### `Planner`\n\n- `Planner.new(config?)`\n- `planner:Compute(startPosition: Vector3, goal, requestOptions?) -> PlanResult`\n\n`PlanResult` returns:\n- `ok`\n- `status`\n- `waypoints`\n- `cost`\n- `computeTimeMs`\n- `blockedLabels`\n- `failureReason`\n\n### `Navigator`\n\n- `Navigator.new(agentModel: Model, options?)`\n- `navigator:MoveTo(goal, moveOptions?)`\n- `navigator:Cancel(reason?)`\n- `navigator:Destroy()`\n- `navigator:GetState()`\n- `navigator:GetDebugSnapshot()`\n\nSignals:\n- `Started`\n- `PathComputed`\n- `WaypointAdvanced`\n- `Replanned`\n- `Blocked`\n- `Stuck`\n- `Completed`\n- `Failed`\n- `Cancelled`\n\n### `Coordinator`\n\n- `Coordinator.new(options?)`\n- `coordinator:Register(navigator)`\n- `coordinator:Unregister(navigator)`\n- `coordinator:RequestRepath(navigator, reason?)`\n- `coordinator:SetTargetSpacing(key, radius, slotCount?)`\n- `coordinator:Destroy()`\n\n## Tuning Notes\n\n- `maxRequestsPerSecond` limits total path computations through a shared coordinator.\n- `perNavigatorCooldown` stops one agent from monopolizing the queue.\n- `moveTimeout` and `maxReplans` control how aggressively a navigator recovers from getting stuck.\n- `followMovingGoal` makes a navigator periodically re-evaluate a moving `BasePart` or `Attachment` target.\n- `movingGoalThreshold` is the target drift in studs before a moving-goal replan is requested.\n- `movingGoalRepathInterval` is the minimum time between moving-goal replans.\n- `SetTargetSpacing` only affects explicit spacing keys or `BasePart` / `Attachment` goals. Raw `Vector3` goals need `moveOptions.spacingKey`.\n\n## Guarantees\n\n- `MoveTo` is non-yielding.\n- Starting a new `MoveTo` cancels the old run with reason `Replaced`.\n- Blocked paths only trigger replans for waypoints ahead of the current waypoint.\n- Crowd support in v1 is coordination-first: shared budgets, staggered repaths, and spacing slots.\n\n## Non-goals for v1\n\n- Steering-based local avoidance between moving agents\n- Full crowd simulation\n- Non-humanoid movement controllers\n\n## Example Project\n\nThe root `default.project.json` syncs a demo place that mounts:\n- the package under `ReplicatedStorage.Packages.PathfindingPlus`\n- example scripts under `ServerScriptService.PathfindingPlusExample`\n\nThe demo script builds three scenes:\n- a single-agent corridor\n- a blocked-path replan demo\n- a crowd chokepoint demo\n\n## Development\n\nInstall the local toolchain:\n\n```bash\naftman install --no-trust-check\n```\n\nRun checks:\n\n```bash\nstylua --check src test example\nselene src test example\nlune run test/run.luau\nwally install\nwally package --list\nrojo build default.project.json --output PathfindingPlus.rbxlx\n```\n","readmeTruncated":false}