Skip to content

Add optional async mob pathfinding#14029

Open
Rxflex wants to merge 1 commit into
PaperMC:mainfrom
Rxflex:feature/async-pathfinding
Open

Add optional async mob pathfinding#14029
Rxflex wants to merge 1 commit into
PaperMC:mainfrom
Rxflex:feature/async-pathfinding

Conversation

@Rxflex

@Rxflex Rxflex commented Jul 3, 2026

Copy link
Copy Markdown

Summary

Adds an opt-in feature that moves the expensive A* search in mob pathfinding
(PathFinder#findPath) off the main server thread onto a worker pool. Gated
per-world behind entities.behavior.async-pathfinding (default off).

How it works

  • The request is prepared on the main thread (validation, world-border
    check, EntityPathfindEvent, PathNavigationRegion snapshot).
  • Only the expensive A* search runs on a worker pool, using a
    thread-confined PathFinder created per call — the shared, mutable
    NodeEvaluator on this.pathFinder is never touched off-thread.
  • The finished Path is applied back on the main thread via the server
    executor, so the world mutation model is unchanged.
  • Only the create-and-apply moveTo(coords/entity, speed) overloads opt in;
    createPath(...) stays fully synchronous, so goals that inspect the path
    directly keep exact vanilla behaviour.

Safety / no-regression

  • Exceptions in the worker fall back silently (mob recomputes next time).
  • The pool uses a caller-runs policy with a bounded queue, so a saturated
    queue degrades to vanilla synchronous pathfinding — never worse than baseline.
  • Default off; zero behavioural change unless explicitly enabled.

Measured impact

Synthetic in-process benchmark (200 mobs, obstacle field, hard targets),
per-path main-thread cost:

main-thread cost / path
sync (async off) ~1003 µs
async (async on) ~91 µs

~90% of main-thread pathfinding cost removed on expensive paths (the case
that actually causes MSPT spikes: obstacle-dense areas, hard/unreachable
targets, villages/farms). On trivial paths the offload overhead makes it
roughly neutral — hence the opt-in default.

Notes

  • This is an experimental, opt-in feature; it has not yet been validated under
    a real multiplayer load, only via the isolated microbenchmark above.
  • Reading the live region/mob off-thread carries an accepted, bounded
    data-race tradeoff (as shipped by other forks), mitigated by the try/catch
    fallback.
  • Follow-up: a thread-local PathFinder pool would cut the residual ~91 µs
    prep (dominated by per-call NodeEvaluator allocation) further.

Offload the A* search in PathFinder#findPath off the main server thread
for mob navigation, gated per-world behind
entities.behavior.async-pathfinding (default off).

The request is prepared on the main thread (validation, EntityPathfindEvent,
region snapshot) and only the expensive A* search runs on a worker pool
using a thread-confined PathFinder instance; the finished Path is applied
back on the main thread via the server executor. Failures fall back
silently and the pool uses a caller-runs policy, so a saturated queue
degrades to vanilla synchronous behaviour and never regresses past it.

On expensive pathfinding (obstacle-dense areas, hard/unreachable targets)
this removes ~90% of the per-path main-thread cost (measured ~1003us -> ~91us
per path in a synthetic obstacle field). On trivial paths the offload
overhead makes it roughly neutral, hence the opt-in default.
@Rxflex Rxflex requested a review from a team as a code owner July 3, 2026 23:10
@github-project-automation github-project-automation Bot moved this to Awaiting review in Paper PR Queue Jul 3, 2026
@mbax

mbax commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Has this been tested on a running server?

How much of this as AI-generated?

@Rxflex

Rxflex commented Jul 6, 2026

Copy link
Copy Markdown
Author

Yes, but on static server, i don't have enough ppl to test performance, i think it's 40-50% ai generated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Awaiting review

Development

Successfully merging this pull request may close these issues.

2 participants