Skip to content

Instantly share code, notes, and snippets.

@EvanBalster
Last active April 12, 2026 07:32
Show Gist options
  • Select an option

  • Save EvanBalster/ea51ddf9c80c3caf730ef83a95a638e2 to your computer and use it in GitHub Desktop.

Select an option

Save EvanBalster/ea51ddf9c80c3caf730ef83a95a638e2 to your computer and use it in GitHub Desktop.
Recast Navigation hack for Long-Range Off-Mesh Connections

This is a drop-in hack for enabling long-range offmesh connections in an application using the unmodified Recast Navigation library. This avoids the need to maintain a fork of the library if your game features portals, trains, non-euclidean geometry or some such.

It works by injecting a private method into dtNavMesh, and relies on implementation details of the Detour library which may change in the future. However, the implementation details in question have been stable for three years so this is unlikely to happen any time soon.

The code is based on PR #645 by niji-k.

WARNING

This manual linking mechanism is brittle. If you are loading and unloading navmesh tiles at runtime you must take care to 'unconnect' any long-range links you create, or you may encounter null-pointer crashes when querying the navmesh.

Instructions

Any source files responsible for building the navmesh should #include "Detour_HACK_OffMeshLinks.h" before including DetourNavMesh.h. The easist way to do this is to include the hack at the top of the C++ files concerned.

After building any pair of navtiles sharing a long-range offmesh connection, call dtNavMesh::connectManualOffMeshLinks.

  • This is unnecessary, but harmless, if the tiles are adjacent.
  • You may convert dtTileRef to dtMeshTile* pointers by calling dtNavMesh::getTileByRef.
  • It is usually necessary to call this function a second time with the order of the tiles swapped.
  • As usual, make sure to create a zero-cost or low-cost area type if these long-range connections represent portals or high-speed transit.

Before unloading a navtile, go through any long-range neighbors and call dtNavMesh::unconnectManualOffMeshLinks.

  • The first argument should be the neighboring tile and the second should be the one about to get unloaded.
  • Don't do this if the neighboring tile is already unloaded.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment