Repository navigation
build(deps)!: move Maul Nav to 1.2.0 - #222
Conversation
The engine's navigation module takes Maul Nav 1.2.0's names, argument orders and defs: a navmesh made from its own def that holds the bake def, and avoidance velocities in binary32. Tiles bake under a later generator and tile format, so the navmesh fingerprint moves. BREAKING CHANGE: a navmesh's tile bytes and fingerprint change, and avoidance velocities are rounded to binary32, so a game's agents that avoid each other move by different amounts.
siracozmen01
left a comment
There was a problem hiding this comment.
Review at c285aae: ready, with one point not verified. No findings. Read, not run. The vendored tree's identity with the archive was checked by the manager.
The engine's calls, against the vendored 1.2.0 headers:
mnavAvoidance_Avoid(avoidance, agents, count, obstacles, obstacleCount, step, mnavVec2* velocitiesOut)(avoidance.h).mnavAgent.velocityandpreferredaremnavVec2.velocityOfrounds each part once, and the velocities vector is nowmnavVec2, widened on the way out.mnavNavmesh_FindNearest(navmesh, point, halfExtents, filter, out)andmnavQuery_FindPath(query, navmesh, startPolygon, start, endPolygon, end, filter, out)match the new argument orders, with the filter NULL in both.mnavNavmeshDefhasbake,tierandlimits.mnavNavmeshDefResulthassettingandbakeSetting, and the latter ismnav_bakeSettingNoneunless the setting ismnav_navmeshSettingBake, so the new context is harmless otherwise.- The memory budget is set on both the navmesh's limits and the bake def's limits. The bake def still goes to
mnavCreateBaker, and the navmesh def's comment says the allocator, limits and clock inbakeare the bakers'. mnavBakeReport.polygonCount,mnavBaker_BakeTileandCopyTile,mnavNavmesh_StageTile,StageTileRemovalandCommitare pure renames.mnavHash64takesint64_t, and every count passed fits.
The golden move is explained by Maul Nav's changelog at v1.2.0:
- 0.2.0 baked under tile format 3 and generator 3.
- 0.6.0 sets
MNAV_BAKE_GENERATOR4, 0.7.0 sets 5, and 0.8.0 sets 6 withMNAV_TILE_FORMAT4. Each is entered as changing every tile's bytes and fingerprint. The vendored base.h/bake.h define format 4 and generator 6. - 0.8.0 leaves polygons and links unchanged, and 0.7.0 only adds polygons on one-cell strips the test scene does not have. That fits a path that stays four points and 31.895 m.
- 1.0.0 to 1.2.0 change no tile bytes (1.0.0 says so outright, and 1.0.1 to 1.2.0 are query, corridor, wall and link fixes).
The body's per-release account matches the changelog's breaking entries. The 1.1.3 claim holds in the code: Navmesh::path returns an empty Path when either nearest fails (navmesh.cpp:263), so mnavQuery_FindPath only ever sees points FindNearest snapped onto the navmesh, never one past 1e100 m.
Not verified: that no other doc or source outside third_party/ still names Maul Nav 0.2.0 or an old call (mnavFindPath, mnavFindNearest, mnavAvoid(, mnavBakeTile, mnavCopyBakedTile, mnavStageTile, mnavCommit, mnavDefaultBakeDef used for a navmesh). dependencies.md is updated. I cannot search the tree, and a build would catch a stale call but not a stale doc.
The ! and the BREAKING CHANGE footer fit a dependency move that changes results. No line of the body starts a commit header.
🤖 I have created a release *beep* *boop* --- ## [0.7.0](v0.6.1...v0.7.0) (2026-11-05) This release moves the engine to Maul Nav 1.2.0, Maul UI 1.3.3 and Maul Unicode 1.1.2. A navmesh's tiles bake to new bytes, and agents that avoid each other move by slightly different amounts. No wire, save, checkpoint or cooked format changes, and the engine keeps no baked tile across runs. ### Changed - **Breaking:** The engine is built on Maul Nav 1.2.0, from 0.2.0, vendored from its release archive with its SHA-256 checked. `rawframe/navigation`'s API does not change. What a game sees change ([#222](#222)): - A navmesh's tile bytes and fingerprint change: tiles bake under generator 6 and tile format 4. The fingerprint a server reports in its `navigation_summary` record moves. - A walkable strip one cell thin now gets a polygon, so a path may cross it, and heights along long edges are sampled more finely, which reaches the height of a path's points over uneven ground. Paths over the same polygons are otherwise unchanged. - Avoidance velocities are rounded to binary32 and never pass an agent's maximum speed, so a game's agents that avoid each other in `rawframe.navigation.avoid`, as tycoon's customers do, move by slightly different amounts each step. - A navigation query past 1e100 m from the navmesh's origin finds nothing. - The engine is built on Maul UI 1.3.3 and Maul Unicode 1.1.2, each vendored from its release archive with its SHA-256 checked. Maul Window, Maul Tween and Maul RHI stay at 0.12.0, 1.0.0 and 0.15.0. Layouts, styles, draw lists, line breaks, shaped text, glyph images and the accessibility tree are unchanged; line breaking takes 1 to 2% longer, since Maul Unicode now checks every iterator it is given ([#221](#221)).
Problem
The engine pins Maul Nav 0.2.0. Maul Nav 1.2.0 is released and verified. Between them lie eight breaking 0.x releases (0.3.0 to 0.8.0, and the 0.8.x fixes), then 1.0.0, which settles the API.
Change
third_party/maul-navis Maul Nav 1.2.0. It was vendored withtools/update_maul.sh maul-nav maul-nav-1.2.0.tar.gz, which checked the archive against the release'sSHA256SUMS. The archive has one attestation on GitHub, and its tag is the commitdocs/operations/dependencies.mdnow gives.modules/navigation/src/navmesh.cppandavoidance.cpp, the engine's only Maul Nav callers, take 1.2.0's API.rawframe/navigation's public API does not change, and nothing above it changes.modules/navigation/tests/navmesh_test.cpp: the navmesh fingerprint golden moves from0x530d3bbdede27404to0x4a35ccb805b9f2fb. The test's path is unchanged: four points, the same corners, 31.895 m. Only the tile bytes it hashes moved.Every breaking release, against the engine's calls
The engine calls, before and after:
mnavDefaultBakeDef,mnavCreateNavmesh(&bakeDef, ...)mnavDefaultNavmeshDef, itsbakethe bake def,mnavCreateNavmesh(&navmeshDef, ...)mnavCreateBaker(&bakeDef, ...),mnavCreateQuery,mnavCreateAvoidancemnavBakeTile,mnavCopyBakedTilemnavBaker_BakeTile,mnavBaker_CopyTilemnavStageTile,mnavStageTileRemoval,mnavCommitmnavNavmesh_StageTile,mnavNavmesh_StageTileRemoval,mnavNavmesh_CommitmnavFindNearest(navmesh, filter, point, halfExtents, out)mnavNavmesh_FindNearest(navmesh, point, halfExtents, filter, out)mnavFindPath(query, navmesh, filter, startPolygon, start, endPolygon, end, out)mnavQuery_FindPath(query, navmesh, startPolygon, start, endPolygon, end, filter, out)mnavAvoidmnavAvoidance_AvoidmnavHash64(seed, data, int32_t)mnavHash64(seed, data, int64_t)0.3.0
mnavAgent.velocityandpreferredand the velocities written aremnavVec2. The engine rounds eachGroundvelocity to binary32 once on the way in, and widens each one written back.rawframe.navigation.agententities avoid each other in therawframe.navigation.avoidsystem, as tycoon's customers do, sees them move by slightly different amounts each step.mnavNavmesh_FindNearest's andmnavQuery_FindPath's outputs only on success, and treats a failed nearest as none found, as before.mnavWall, tile and cell ranges, andmnavBaker_CopyTilerefusing an empty baker withmnav_errorState: none are reached. The engine copies a tile only after a successful bake.0.4.0
mnavNavmeshDef. The engine'stier(dynamic) andlimits.tilesmove there from the bake def, andlimits.memoryBytesis set on both the navmesh's and the bake def's, as the shared def gave both before. Each of the navmesh and its baker keeps its own budget, as it did. The engine also reports the refused bake setting a navmesh def names.stage.0.5.0
mnavBaker_CopyTileis the engine's only such call, and it copies into a buffer of exactly the size it just measured.mnavBakeSetting's values are renamed, but the engine reports only the number.mnavHash64takes anint64_tcount. Its result is unchanged for every count that fits in anint32_t, which every tile does.0.6.0
int32_t, and report counters are named...Count: the engine readsreport.polygonCountwhere it readpolygons.MNAV_BAKE_GENERATOR4 changes every tile's bytes and fingerprint. The engine's bake def takes Maul Nav's defaultmaxEdgeLength(12 m) anddetailSampleDistance(1.5 m), both far above the changed range at the engine's 0.2 m cells (below one cell, and below a sixteenth of one), so only the generator byte moves for that reason.0.7.0
MNAV_BAKE_GENERATOR5 moves every tile's bytes again, and a game's navmesh gets a polygon where such a strip had none, so a path may now cross it.0.8.0
MNAV_TILE_FORMATis 4 andMNAV_BAKE_GENERATORis 6. Polygons and links do not change, so paths cross the same polygons. Heights read from the detail surface move along edges that now carry more samples, which reaches the height of a path's points over uneven ground. Tiles grow by about 4%.navigation_summaryrecord moves, and no test reads its value.0.8.1 to 0.8.6
Each fix concerns a call the engine does not make, or input it never gives. None is reached:
mnavQuery_ReplanCorridor.mnavGridFlow_Update.mnavSteer.mnavSetCorridorand corridors.mnavDebugPath.1.0.0 to 1.2.0
mnavQuery_FindShortestPath's corridor. The engine searches withmnavQuery_FindPath, so it is not reached.mnavPathgainsqueryandgeneration. The engine readsend,pointsandpointCount.mnavSetCorridor,mnavDebugPathandmnavSteerare not used.MNAV_NODISCARDunder GCC 14 in C23. It changes what Maul Nav's own C is warned about, not results.mnavQuery_FindShortestPathfar from the origin. Not reached.mnav_errorLimit, where it gave a wrong answer.Navmesh::nearestgives none for such a point, andNavmesh::pathan empty path, as for a point off the navmesh. A Kest program'sNavigation.nexttoward a point past 1e100 m now finds no way instead of a wrong one.mnavQuery_GenerateLinkson a navmesh baked with agent radius 0. Not used.No wire, save, checkpoint or cooked format changes: no navmesh tile is saved or cooked.
Verification
navigation's tests: with the old golden,APathGoesAroundAWallAndStraightOnceItIsGonefailed only at the fingerprint, with the path unchanged: 4 points, the same corners, 31.895 m. The new value holds in every tree below, so the bytes are the same on Clang, GCC 14 and wasm32.tools/check.sh fullpassed at four jobs through the heavy-job wrapper, in 1596 s:clang-thread: 208 of 208.clang-sanitize: 253 of 253.gcc-debug: 208 of 208.clang-development: 208 of 208 unit tests and 19 of 19 integration tests. Those include tycoon's bots, whose server runsrawframe.navigation.avoidand reports itsnavigation_summary.wasm-development: 62 of 62.gcc-debug: 76 C objects, no warning.BREAKING CHANGE: the engine is built on Maul Nav 1.2.0. A navmesh's tile bytes and fingerprint change: tiles bake under generator 6 and tile format 4. A walkable strip one cell thin now gets a polygon, and heights along long edges are sampled more finely. Avoidance velocities are rounded to binary32 and never pass an agent's maximum speed, so a game's agents that avoid each other move by slightly different amounts. A navigation query past 1e100 m from the navmesh's origin finds nothing.