Repository navigation
Releases
v1.2.0
1.2.0 (2026-11-05)
This release makes mnavQuery_GenerateLinks find jumps across gaps on
a navmesh baked with an agent radius of 0. Links change only on such a
navmesh; at any radius above 0 they are the same.
Changed
mnavQuery_GenerateLinkslands neither a drop nor a jump on the
polygon it starts from. On a navmesh baked with an agent radius of 0,
whichmnavAgentProfileallows, the jump search's first landing box
lay on the edge itself, where only the takeoff's polygon is, so the
search stopped there and never reached the far side of a gap: with
detouron, the link was dropped, and withdetour0 it was kept as
a jump of two cells onto the polygon it starts from. On the trench of
the link generation tests (a 1.2 m gap), baked with radius 0, there
were no jumps across the gap, or 105 jumps onto the slab they start
from withdetour0; there are now 16 jumps across and 18 back. At
any radius above 0, the links are the same as 1.1.3's.
(#365)
v1.1.3
1.1.3 (2026-11-05)
This release gives the navmesh queries a range: a point, end, center or
radius more than MNAV_MAX_QUERY_DISTANCE (1e100 m) from the navmesh's
origin is now refused with mnav_errorLimit. Such input used to give
wrong results. Results within the range do not change.
Fixed
- The navmesh queries took any finite point, end, center or radius,
and far from the navmesh their arithmetic overflowed:
mnavQuery_MoveAlongSurfacetoward an end near ±1e308 reported
mnav_moveReachedat the end itself, off the navmesh;
mnavQuery_FindWallDistanceandmnavQuery_FindWallsfound no wall
from a center 1e154 m away with a radius that covers every wall; and
mnavQuery_FindRandomPointAroundfrom a center 1e155 m or more away
returned the center itself, off the navmesh. The queries now have a
range, as the bake has an extent.MNAV_MAX_QUERY_DISTANCE, 1e100 m,
is how far a query's points, ends, centers and radii may reach from
the navmesh's origin (its bake def's origin) on each axis; within it,
no query's arithmetic overflows. Every navmesh query that takes a
point, end, center or radius refuses one past it with
mnav_errorLimit, after its checks for NULL and non-finite input, and
every corridor call that takes the navmesh refuses a corridor whose
position or target lies past it. The end ofmnavQuery_Raycastand
mnavQuery_MoveAlongSurfaceis measured by its x and z.
(#359)
v1.1.2
1.1.2 (2026-11-05)
This release stops mnavQuery_FindShortestPath from opening nodes past
its path length toward an end far away. No result changes for a caller
that keeps the contract.
Changed
mnavSetCorridor's documented failures no longer list a path whose
first or last point is not finite. A path's points lie in its
context's memory, and only the context's searches write them, so a
path handed back as the contract allows never has one. A path whose
points are an array of the caller's own is still refused with
mnav_errorInvalid. No result changes for a caller that keeps the
contract.
(#350)
Fixed
mnavQueryLimits.pathLengthpromises that no node is opened whose way
from the start and on to the end is longer, but
mnavQuery_FindShortestPathopened such nodes toward a finite end
past about 1e308 m. Its estimate of the way through an interval
overflowed to NaN there, and a NaN estimate passed the length test.
The estimate is now infinite for a root or end more than about 1e154 m
from the interval's end. That is pastMNAV_MAX_PATH_LENGTH, which
caps every search's length, so no node within a limit is turned away.
No result changes: the path given was already right.
(#354)
v1.1.1
1.1.1 (2026-11-05)
This release makes MNAV_NODISCARD the [[nodiscard]] attribute in
GCC 14's C23 mode, so that a C program built with GCC 14 is warned
when it drops a status the library returns.
Fixed
MNAV_NODISCARDis meant to make every function that returns a
status warn when its result is dropped. In C, it expanded to
[[nodiscard]]only when__STDC_VERSION__was at least202311L.
GCC 14 has the attribute in its C23 mode but reports
__STDC_VERSION__as202000Lthere, so under GCC the macro was
empty, and a program built with GCC 14 could drop any status from
the library without a warning. Clang 20 reports202311L. In C,
the macro is now the attribute in any dialect after C17 whose
compiler defines__has_c_attributeand reportsnodiscard. C17
and older dialects keep the empty expansion, and C++ is unchanged.
(#346)
v1.1.0
1.1.0 (2026-11-04)
This release changes which walls the wall queries report on a navmesh
with floors over each other, and makes a query context keep the last
path a search gave, so that mnavSetCorridor checks a path against it.
A query context holds 76 bytes more per node. Wall distances and lists
change only where a wall of another floor was reported, and steering
changes only where a corner lies past 2^500 of the origin.
Added
mnavPathgains two fields at its end, which the search that gives
the path sets:query, the context that keeps it, andgeneration,
which of that context's paths it is.
(#334)
Changed
mnavQuery_FindWallDistanceandmnavQuery_FindWallscount a wall
only on the center's floor. They no longer report a wall whose
nearest point is more than the agent's step height below, or more
than the agent's height above, the center's height on its polygon,
for the agent the navmesh's tiles are baked for. There is no new
setting, and a center off its polygon is taken at its own height.
Both calls keep the whole radius and one search, so
mnavQuery_FindWallsstill lists every wall it counts, nearest
first, and its first ismnavQuery_FindWallDistance's. On a two-floor
building, a point on the ground under the upper floor's edge was
given that edge, 0.60 m away on the ground and 3 m overhead, where
its nearest ground wall is 1.38 m away; it now gets the ground wall.
(#340)- A query context holds 76 bytes more per node of
limits.nodes, plus
24 bytes, for the kept path's arrays: about 23% more than the 332
bytes per node it held, 623 KB more at the default 8192 nodes. Hosts
that size their contexts by memory should allow for it.
(#334) - The headers of
mnavDebugPath,mnavDebugFlightPathandmnavSteer
say the value they take may be the caller's own: its arrays are the
caller's memory, read only within the counts given, every point
checked;mnavSteercompares a link'spointand never follows it.
(#335)
Fixed
mnavSetCorridortrusted the pointers and counts of a path handed
back to it. A count copied from a longer path read past the
context's buffer: a path from a context of 4 nodes given the polygon
count of a 10-polygon path read 120 bytes past it. A path's arrays
also did not last until the context's next search as documented:
mnavQuery_FindCorridorCornersandmnavQuery_FindCorridorAreas
wrote their corners over a path's points and links, and
mnavQuery_RaycastandmnavQuery_MoveAlongSurfacetheir polygons
over its corridor, so a path loaded after a raycast with the same
context gavemnav_successwith the ray's polygons, and a flight
path's points changed when the same context then found a corridor's
corners. A query context now keeps the last path a search gave in
arrays only a search writes, andmnavSetCorridorchecks the path
against its context before reading any array:mnav_errorStalewhen
a later search of the context has replaced it, and
mnav_errorInvalidfor a path with no context, arrays other than the
ones the context keeps, or more polygons, points or links than it
kept. The corridor is unchanged on any failure.
(#334)mnavDebugPathandmnavDebugFlightPathare documented to refuse a
path with no points withmnav_errorInvalid, but a path whose
pointCountwas 0 drew nothing and returnedmnav_success. They
now refuse a path with fewer than one point, and with no array.
(#335)mnavSteeraccepts any finite corner, but the ground distance
between two finite corners could overflow: with corners
(-1e308, 0, 0)then(1e308, 0, 0)it returnedmnav_steerMoving
with a velocity whose x was NaN, and with corners around 1e200 a zero
velocity, still reported as moving. Each pair of corners is now
measured on its own, a far pair by half its difference scaled by a
power of two, so no two finite corners overflow. Every result where
all corners lie within 2^500 of the origin is bit for bit unchanged.
Distances between near corners no longer depend on a far corner
elsewhere in the list. Anticipating a turn toward a corner past about
1e154 m, where the turn was lost to the overflow, now swings wide as
it does for the same turn nearer.
(#337)
v1.0.1
1.0.1 (2026-11-03)
This release fixes the corridor of a shortest path that ran straight
through a corner where polygons meet. Only such a path's polygons
change; its points, cost and length do not, and no other result
changes.
Changed
- The doc comments of
mnavAvoidance_Avoidand
mnavAvoidance_Avoid3Dstate the fixed exit of an agent exactly on
an obstacle's center: along -Y (ground -Z) on a circle's center, and
along -Z on a sphere's. No velocities change.
(#306)
Fixed
mnavPathpromises its polygons as "The polygons from the start
polygon on, each visit once", butmnavQuery_FindShortestPath
could give a corridor that circled a corner before going on. On a
flat floor of the default def over four tiles, the way from
(28.8, 30.4) to (35.2, 33.6) through the corner (32, 32) had the
right points and length but listed 7 polygons, where
mnavQuery_FindPathgives 3. Rounding made the way that turns at
the corner a little cheaper than the straight one, and that way
reaches the end polygon again only by going round the corner. The
corridor now cuts a polygon visited again back to its first visit,
but never across an off-mesh link's landing, since a link may
genuinely land back in a polygon it left. Only such paths change:
their corridors drop the loop, and their points, cost and length
stay as they were.
(#308)
v1.0.0
1.0.0 (2026-11-03)
This release settles the API: from 1.0.0 there is no 2.0.0. Tile
format 4 and flight tile format 3 keep their version, and a later
1.z library reads every tile a 1.y wrote. No code, tile bytes,
fingerprints or results change from 0.8.6.
Changed
- From 1.0.0,
MNAV_ABI_VERSIONencodes the major and minor version,
and the shared library's SOVERSION is major.minor instead of the
whole version. The CMake package accepts any later 1.z of the same
major version (SameMajorVersion).
(#301) - The tile and flight tile formats keep their version. New data is a
new field with a new tag, never required, and a reader gives an
absent field its default, so a later 1.z library reads every tile a
1.y wrote. A tag the reader does not know is refused with
mnav_errorVersion, and a field whose meaning changes gets a new
tag.
(#301) - The troubleshooting page's
mnav_errorVersionrow covers a tile
carrying a field that a later 1.y release added.
(#301)
v0.8.6
0.8.6 (2026-11-03)
This release fixes what an audit of the debug draws found: a path with
a point that is not finite was drawn instead of refused. No results
change.
Fixed
mnavDebugPathandmnavDebugFlightPathchecked a path's count and
itspointspointer, but not the points themselves. A path with a
point that has a NaN or an infinity was drawn, and the call returned
mnav_successwith NaN and infinite vertices in the buffer. Such a
path is now refused withmnav_errorInvalidbefore anything is
written, so the buffer is left as it was. Paths with finite points
draw as before.
(#294)
v0.8.5
0.8.5 (2026-11-03)
This release fixes what an audit of the corridor code found: a path
with NULL arrays crashed mnavSetCorridor, and corridors with a
position or target that is not finite were used instead of refused.
No results change.
Fixed
mnavSetCorridorchecked that a path has a polygon and a point,
but never checked itspolygonsandpointspointers or the points
it copies. A path with a count of 1 or more and a NULLpolygonsor
pointscrashed it. A path whose first or last point has a NaN was
loaded withmnav_success, leaving the corridor's position or
target NaN. Such a path is now refused withmnav_errorInvalid
before the corridor is touched. Paths frommnavQuery_FindPathand
mnavQuery_FinishPathload as before.
(#290)- No corridor call checked a corridor's
positionandtarget. With
a NaN position or target,mnavQuery_FindCorridorCornersand
mnavQuery_FindCorridorAreasreturnedmnav_successwith a NaN
corner and a NaN area run, and some moves and shortcuts succeeded and
kept the NaN. A well-formed corridor now has a finite position and
target, so every call that checks for a well-formed corridor refuses
one whose position or target is not finite withmnav_errorInvalid.
mnavSetCorridorreplaces both ends, so it does not check them.
(#291)
v0.8.4
0.8.4 (2026-11-02)
This release fixes what a coverage pass found: a query context made
with an allocator that sets only one of its two functions released
memory to the wrong allocator. Paths, tiles and their formats are
unchanged.
Fixed
mnavCreateQuerytook a def whose allocator sets onlyallocor
onlyfree, which every other creation refuses. The context then
gave blocks from the host'sallocto the C library'sfree, or
blocks frommallocto the host'sfree, which corrupts the host's
heap. Such a def is now refused withmnav_errorInvalidbefore
anything is allocated. A def with both functions or neither works
as before.
(#283)