Ownership & lifecycle
One active navigation
start(modId, request) and restore(modId, checkpoint) return a Navigation object for one journey. Call its methods to read, update or stop that journey. If a navigation exists, another start returns BUSY, even with the same MOD ID. Keep the object in your adapter; never persist or share it.
Use a MOD ID matching [a-z][a-z0-9_-]{0,63}. It labels your integration; it does not retrieve or authorize access to a journey by name. A previous object cannot affect a new journey started by the same MOD.
The navigation object is a cooperation boundary between mods, not a security sandbox against code already executing in the same JVM.
| Event | Your adapter's next action |
|---|---|
| Start/restore succeeds | Store the navigation object; register one observer |
Start returns BUSY |
Leave the current navigation alone; show that Navi is in use |
| Refinement is rejected as stale | Read current state; reconsider whether the original change still applies |
| Dimension changes | Keep the same owner and object; the world session continues |
| Terminal update | Discard the navigation object; persist the supplied checkpoint |
| World exits | Finish ordered checkpoint I/O; cancel your background investigation |
| World is entered again | Load that world's checkpoint; explicitly restore, receiving a new object |
Do not turn a failed read, mutation or restore into an unconditional new start. That would lose the caller's intent and could compete with a different owner.
Observe, then act
navigation.observe(callback) replaces that owner's previous observer. Notifications run on the Minecraft client thread: current state on the next observation, subsequent changes, and one terminal update. A terminal update revokes the navigation object before invoking the callback.
Keep the callback short. Pass immutable updates to your UI state and immutable checkpoint bytes to an ordered persistence queue. Do not mutate Navi inside the callback. If a notification requires another command, enqueue it for a later client tick after returning. An executor that runs immediately on its own thread is not sufficient to defer that command.
Observers remain independent of pause and player-facing sounds. An exception in your observer is not retried. NavigationUpdate.End distinguishes ACTIVE, STOPPED, ARRIVED, WORLD_LEFT and FAILED.
Revisions describe the decision you made
replace changes the request. refine changes selected parts while keeping its destination and consumed progress. Both require snapshot.revision() from a successful read.
- For entity waypoint changes, also supply
snapshot.tracking().revision()asobservedTargetRevision. - For a changed transfer network, supply
snapshot.connectionsRevision()to the refinement'snetworkmethod. - An absent waypoint field preserves remaining waypoints; an empty list explicitly clears them.
If asynchronous work returns after cancellation, discard it in your adapter. If Navi rejects an outdated result, read the current state and either recompute against it or end that investigation. Retrying unchanged input is not a recovery strategy.
Persistence belongs to the caller
NavigationCheckpoint is opaque, portable remaining intent. It contains neither a live navigation object nor a worker cache. Store checkpoint.bytes() under your own world and player identity. Do not parse or edit the bytes. NavigationCheckpoint.fromBytes(bytes) constructs a value; Navi validates the format during restore.
Preserve write order. A late write from an old world must not overwrite a newer world's data. Persist terminal checkpoints too: manual stop and arrival clear the remaining intent, whereas world exit can retain it. Ignoring a terminal checkpoint can resurrect an already-finished route. Drain your storage queue before releasing its world owner.
navigation.checkpoint() is available for an explicit save while the navigation object is valid; the terminal observer supplies the final checkpoint after it has been revoked. Checkpoints have a 2 MiB input-size limit. Corrupt or incompatible bytes fail restoration; surface the failure rather than silently starting a different request.
Errors and diagnostics
API calls return NavigationResult.Success or Failure(code, message). Handle known codes such as BUSY, NO_WORLD, INVALID_NAVIGATION, WRONG_THREAD and REENTRANT_OPERATION, and provide a generic fallback for other codes. Invalid DTO construction can throw IllegalArgumentException or NullPointerException before an API call.
Snapshot activity/reason strings are observations, not commands to retry or launch an AI. Unknown values should display a generic status. Ordinary progress updates do not copy the full path.
For optional investigation, use the snapshot's assistance incident rather than elapsed time alone. reportAssistance reports your helper's actual state for that incident; it does not start an assistant. Tie your work to the navigation object, request revision, incident and, for moving targets, target revision. Cancel obsolete work when these no longer describe the current request.