All notable changes to this project are recorded here, grouped as Added, Changed, Fixed, Removed and Security. The project uses Semantic Versioning. Before 1.0.0, any release may change the API, the ABI and the tile formats.
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.
mnavQuery_GenerateLinks lands neither a drop nor a jump on the
polygon it starts from. On a navmesh baked with an agent radius of 0,
which mnavAgentProfile allows, 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
detour on, the link was dropped, and with detour 0 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 with detour 0; 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)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.
mnavQuery_MoveAlongSurface toward an end near ±1e308 reported
mnav_moveReached at the end itself, off the navmesh;
mnavQuery_FindWallDistance and mnavQuery_FindWalls found no wall
from a center 1e154 m away with a radius that covers every wall; and
mnavQuery_FindRandomPointAround from 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 of mnavQuery_Raycast and
mnavQuery_MoveAlongSurface is measured by its x and z.
(#359)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.
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)mnavQueryLimits.pathLength promises that no node is opened whose way
from the start and on to the end is longer, but
mnavQuery_FindShortestPath opened 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 past MNAV_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)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.
MNAV_NODISCARD is 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 least 202311L.
GCC 14 has the attribute in its C23 mode but reports
__STDC_VERSION__ as 202000L there, 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 reports 202311L. In C,
the macro is now the attribute in any dialect after C17 whose
compiler defines __has_c_attribute and reports nodiscard. C17
and older dialects keep the empty expansion, and C++ is unchanged.
(#346)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.
mnavPath gains two fields at its end, which the search that gives
the path sets: query, the context that keeps it, and generation,
which of that context's paths it is.
(#334)mnavQuery_FindWallDistance and mnavQuery_FindWalls count 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_FindWalls still lists every wall it counts, nearest
first, and its first is mnavQuery_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)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)mnavDebugPath, mnavDebugFlightPath and mnavSteer
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; mnavSteer compares a link's point and never follows it.
(#335)mnavSetCorridor trusted 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_FindCorridorCorners and mnavQuery_FindCorridorAreas
wrote their corners over a path's points and links, and
mnavQuery_Raycast and mnavQuery_MoveAlongSurface their polygons
over its corridor, so a path loaded after a raycast with the same
context gave mnav_success with 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, and mnavSetCorridor checks the path
against its context before reading any array: mnav_errorStale when
a later search of the context has replaced it, and
mnav_errorInvalid for 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)mnavDebugPath and mnavDebugFlightPath are documented to refuse a
path with no points with mnav_errorInvalid, but a path whose
pointCount was 0 drew nothing and returned mnav_success. They
now refuse a path with fewer than one point, and with no array.
(#335)mnavSteer accepts any finite corner, but the ground distance
between two finite corners could overflow: with corners
(-1e308, 0, 0) then (1e308, 0, 0) it returned mnav_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)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.
mnavAvoidance_Avoid and
mnavAvoidance_Avoid3D state 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)mnavPath promises its polygons as "The polygons from the start
polygon on, each visit once", but mnavQuery_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_FindPath gives 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)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.
MNAV_ABI_VERSION encodes 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)mnav_errorVersion, and a field whose meaning changes gets a new
tag.
(#301)mnav_errorVersion row covers a tile
carrying a field that a later 1.y release added.
(#301)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.
mnavDebugPath and mnavDebugFlightPath checked a path's count and
its points pointer, but not the points themselves. A path with a
point that has a NaN or an infinity was drawn, and the call returned
mnav_success with NaN and infinite vertices in the buffer. Such a
path is now refused with mnav_errorInvalid before anything is
written, so the buffer is left as it was. Paths with finite points
draw as before.
(#294)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.
mnavSetCorridor checked that a path has a polygon and a point,
but never checked its polygons and points pointers or the points
it copies. A path with a count of 1 or more and a NULL polygons or
points crashed it. A path whose first or last point has a NaN was
loaded with mnav_success, leaving the corridor's position or
target NaN. Such a path is now refused with mnav_errorInvalid
before the corridor is touched. Paths from mnavQuery_FindPath and
mnavQuery_FinishPath load as before.
(#290)position and target. With
a NaN position or target, mnavQuery_FindCorridorCorners and
mnavQuery_FindCorridorAreas returned mnav_success with 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 with mnav_errorInvalid.
mnavSetCorridor replaces both ends, so it does not check them.
(#291)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.
mnavCreateQuery took a def whose allocator sets only alloc or
only free, which every other creation refuses. The context then
gave blocks from the host's alloc to the C library's free, or
blocks from malloc to the host's free, which corrupts the host's
heap. Such a def is now refused with mnav_errorInvalid before
anything is allocated. A def with both functions or neither works
as before.
(#283)This release fixes what an audit of the steering code found: corners with a link count below 0 were steered instead of refused. Paths, velocities, tiles and their formats are unchanged.
mnavSteer refused corners with no points, or with links counted
but no links pointer, but steered corners whose linkCount is
below 0 as if they had no links and returned mnav_success. Such
corners are now refused with mnav_errorInvalid, and steeringOut
is left as it was, as for its other refusals.
(#277)This release fixes what an audit of the flow fields found: a repair given two very long lists skipped its check that their cells lie in the grid. Paths, flow fields, tiles and their formats are unchanged.
mnavGridFlow_Update checked its goals and changed cells in one
loop bounded by goalCount + changedCount, a sum taken in 32 bits.
When the two counts summed past INT32_MAX, a sanitizer build
trapped on the overflow and a Release build checked no cell, so a
cell outside the grid was accepted instead of refused with
mnav_errorInvalid as flow.h promises. Each list is now checked
by its own count. Counts whose sum fits behave as before.
(#274)This release fixes what an audit of the corridor calls found: a replan took a broken search box whenever it did not need the box. Paths, tiles and their formats are unchanged.
mnavQuery_ReplanCorridor checked its halfExtents box only when an
end's polygon was no longer current and had to be found again, so
while both ends were current a box with a half size below 0, a NaN
or an infinity was accepted, and refused only once a commit replaced
the tile under an end. The box is now checked on every call, as
mnavNavmesh_FindNearest checks it, and a bad one is refused with
mnav_errorInvalid, the corridor left as it was.
(#269)This release fixes what an audit of the detail mesh and of the flight
tile loader found. A polygon edge took at most 20 height samples, and
a slanted edge's samples could snap to a gap wider than
detailSampleDistance, so long edges and tile sides were sampled more
widely than asked, silently. Now an edge takes up to 41 samples and a
segment more where snapping leaves a gap, and every edge still sampled
more widely is counted in the bake report. The flight loader refuses a
tile at a place no bake writes.
The tile format rises to 4, so tiles baked by 0.7.0 are refused with
mnav_errorVersion and must be rebaked. The bake generation rises to
6. Polygons and their links are unchanged, so paths cross the same
polygons; heights read from the detail surface change along edges that
now carry more samples. Tiles grow by about 4% at the default def, and
more with a small detailSampleDistance and a detailMaxError near 0.
Flight tiles and their format are unchanged.
detailSampleDistance. maxEdgeLength cuts walls but
not edges between polygons or along a tile side, so even the default
def sampled a tile side of 128 cells more widely than asked. DPRT
now stores the triangle count in 2 bytes, so a polygon's detail
holds up to 255 vertices (MNAV_MAX_DETAIL_VERTICES) and an edge up
to 41 samples (MNAV_MAX_DETAIL_EDGE_SAMPLES), and an edge takes a
segment more while its widest snapped gap passes the distance.
MNAV_TILE_FORMAT is 4 and MNAV_BAKE_GENERATOR is 6.
(#261)detailSampleDistance
went unreported. mnavBakeReport.coarseEdgeCount now counts each
such edge once, before regionsDropped, which changes the struct's
layout. bake.h names the detail caps, and detailSampleDistance
says what an edge takes and what is counted.
(#259)mnavFlightVolume_StageTile took a flight tile's place as any 32-bit
value, and mnavFlightVolume_FindNearestPoint then overflowed a
32-bit product for a tile placed far enough. The loader now refuses,
with mnav_errorFormat in the header, a place whose frame the bake
refuses, as a navmesh tile's place is checked.
(#263)This release fixes what an audit of the status codes and a differential check of tile sides found. A walkable region one cell thin is no longer dropped by the bake, so neighboring tiles agree on their shared side; this raises the bake generation to 5. A debug buffer counts triangles and lines, not indices, and link generation gives a measuring call room at the link limit instead of a refusal.
No tile format rises, so tiles baked by 0.6.0 load as they are. Every tile's fingerprint differs from a new bake's, so a host that keeps tiles by fingerprint rebakes them once. Paths, corridors, flow fields, links and velocities are unchanged, except on tiles with a walkable region one cell thin, which now gets a polygon where it had none.
maxEdgeError left with two vertices, was dropped by the
contour stage without a count. On a tile side, the neighboring tile
kept the same cells in a wider region, so its side edge faced nothing
and acted as a wall. Now such a region keeps the outline of its
cells, and the walls round it are simplified within 0 where they meet
it. MNAV_BAKE_GENERATOR is 5, so every tile's bytes and fingerprint
change.
(#254)mnavDebugBuffer's triangleCapacity and
triangleCount counted indices, three a triangle, and lineCapacity
and lineCount two a line, while their names and
mnavTriangleMesh.triangleCount count triangles. Now they count
triangles and lines: a host gives room for 3 * triangleCapacity and
2 * lineCapacity indices and draws 3 * triangleCount and
2 * lineCount. The geometry drawn is unchanged.
(#237)mnavQuery_GenerateLinks with a buffer too short could
stop with mnav_errorLimit at MNAV_MAX_LINKS while a call with room
for every link succeeds, since the count past a short buffer also
holds near duplicates. Now such a call gives mnav_errorCapacity with
a count of MNAV_MAX_LINKS, and mnav_errorLimit comes only with a
buffer that holds every link counted.
(#248)mnavQuery_GenerateLinks promised its count past a short buffer was
the number of links generated. The filterDistance rule compares a
link only with those held in the buffer, so that count may be more
than a long enough buffer keeps. linkgen.h and the navmesh guide
now say the count is room enough for a second call, which then holds
every link a long buffer keeps.
(#239)This release brings maul-nav in line with the family rulings of the 1.0.0 reviews. Every enumeration typedef is a 32-bit integer, and every counter is named for what it counts. A bake now keeps a very short edge length or sample distance in force, which raises the bake generation to 4. A commit or destroy no longer frees a tile while its ids are still live.
No tile format rises, so tiles baked by 0.5.0 load as they are. Their
fingerprints differ from a new bake's, so a host that keeps tiles by
fingerprint rebakes them once. Paths, corridors, flow fields and
velocities are unchanged, except on tiles baked with a
maxEdgeLength below one cell or a detailSampleDistance below a
sixteenth of a cell, whose polygons or detail now differ.
mnavAreaType is
int32_t, where it was uint8_t (mnavDebugKind was uint16_t).
This changes the layout of every struct that holds one.
(#230)mnavDebugKind; mnavBakeSetting,
mnavVolumeKind, mnavInputElement, mnavInputKind and
mnavBakeStage; mnavFlightSetting, mnavFlightVolumeSetting and
mnavFlightStop; mnavTier, mnavNavmeshSetting,
mnavTileSection and mnavLinkKind; and mnavPathEnd,
mnavMoveEnd, mnavSteerState and mnavRayEnd.mnav_errorInvalid, like
one past the last: the navmesh def's tier, mnavLinkDef.kind, the
link generation def's dropKind and jumpKind, and
mnavBakeVolume.kind. A query filter never lets a negative link
kind through.mnavDebugVertex.value is uint32_t, and the vertex is 20 bytes. A
corridor polygon's value is its place, no longer modulo 65536, and a
flight block's value is its side, no longer capped at 65535.mnavAreaType stays uint8_t: it is a number the host chooses,
from 0 to MNAV_AREA_TYPES - 1.thingCount or thingDropped. Measures (tileBytes, memoryPeak,
stageTicks, stageMemory) and the def limits keep their names.
(#231)mnavBakeReport: triangleCount, spanCount, regionCount,
polygonCount, vertexCount, detailVertexCount,
detailTriangleCount, holesDropped, regionsDropped,
partialRingCount, fallbackHeightCount and cappedDetailCount.mnavFlightBakeReport: triangleCount, spanCount, cubeCount,
nodeCount and leafCount.mnavHierarchyReport: clusterCount, transitionCount,
edgeCount and searchCount.mnavLinkState.crossings is crossingCount.mnavFound.count, mnavWallsFound.count and mnavCorridor.count
are polygonCount, wallCount and polygonCount.maxEdgeLength below one cell, or a positive
detailSampleDistance below a sixteenth of a cell, rounded down to 0
and turned the setting off. Now such a length limits walls to one
cell, and such a distance samples every cell. MNAV_BAKE_GENERATOR is
4, so every tile's fingerprint changes.
(#218)MNAV_MAX_EDGE_ERROR names the bound on maxEdgeError, which was
checked without a name.mnavBakeDef states its range. limits.tileTriangles
names MNAV_MAX_INPUT_TRIANGLES as its bound.mnavDestroyNavmesh, and a flight volume's
commit and destroy, did the same. Now each makes the ids stale first:
a free hook reads mnav_errorStale for a navmesh polygon, and
mnav_errorNotLoaded for a flight tile that is gone.
(#227)This release finishes the API review for 1.0.0. A call that fills a caller's array now zeroes it over its capacity when it fails, and a refused debug call leaves its buffer as it was. The bake def's setting values carry the def's name, and the family's hash takes a 64-bit byte count.
On success nothing changes: tile bytes, fingerprints, paths, debug geometry and velocities are the same, and no tile format rises, so tiles baked by 0.4.0 load as they are.
mnavNavmesh_FindPolygons, mnavQuery_FindWalls,
mnavQuery_FindCorridorAreas, mnavQuery_GenerateLinks,
mnavBaker_CopyTile and mnavFlightBaker_CopyTile.mnav_errorCapacity), which writes what
fits and counts what the whole needs.
(#209)mnavNavmesh_DebugCorridor used to append the polygons before a
malformed id and then refuse the run. It now checks every id before
it draws.mnavNavmesh_CheckCorridor's count is named validCountOut; no
call changes.mnavBakeSetting's values are named for the bake def,
beside the navmesh's, flight's and flight volume's settings. Their
numbers do not change.
(#211)mnav_settingCellSize is mnav_bakeSettingCellSize, and so on for
all 22: mnav_bakeSettingNone, Cookie, Allocator, Origin,
CellSize, CellHeight, TileCells, AgentRadius, AgentHeight,
AgentStepHeight, AgentMaxSlope, InputTriangles,
TileTriangles, TileSpans, TilePolygons, TileVertices,
MemoryBytes, MinRegionArea, MaxEdgeError, MaxEdgeLength,
DetailSampleDistance and DetailMaxError.mnavHash64 takes its byte count as an int64_t, where
it took an int32_t, so it hashes 2 GiB or more in one call. Its
result for every count that fit in an int32_t is unchanged.
(#214)This release settles the last API changes planned before 1.0.0.
- Navmeshes and flight volumes are made from defs of their own.
- Any number of query contexts can search one hierarchy at once.
- A refused bake input is named by its kind and index.
- The grid flow field is mnavGridFlow.
- A call refused as busy from host code writes none of its outputs.
Tile bytes, fingerprints, paths, flow fields and velocities do not change, and no tile format rises: tiles baked by 0.3.0 load as they are.
mnavNavmeshDef, from
mnavDefaultNavmeshDef(), and a flight volume from an
mnavFlightVolumeDef, from mnavDefaultFlightVolumeDef(). Before,
each used its baker's def, whose allocator, memory budget, tier and
limits it shared with the bakes.
(#191)bake, the def its tiles are baked with;tier;limits (tiles, tileLinks, links and memoryBytes).mnavBakeDef.tier;tiles, tileLinks and links from mnavBakeLimits.memoryBytes.flight (the flight
def), and limits (tiles and memoryBytes).
mnavFlightLimits.tiles moves there.mnavCreateNavmesh returns an mnavNavmeshDefResult: the status,
the refused mnav_navmeshSetting*, and for
mnav_navmeshSettingBake the bake def's setting.
mnavCreateFlightVolume returns an mnavFlightVolumeDefResult the
same way.mnavBakeSetting loses the tier and the three limits, and the
settings after them are renumbered. mnavFlightSetting loses
mnav_flightSettingTiles.MNAV_MAX_TILES, MNAV_MAX_TILE_LINKS, MNAV_MAX_LINKS and
mnavTier move to navmesh.h.mnavInputResult gains kind, an mnavInputKind
(mnav_inputMesh, _Terrain, _Volume, _Outline or
_Obstacle).index is now the input's index, and the old index, the
element within the input, is elementIndex.mnavBakeReport and mnavFlightBakeReport lose mesh; read
input.kind and input.index.mnavValidateTriangleMesh and mnavValidateOutline are replaced by
mnavValidateBakeInput and mnavValidateBake2DInput, which check a
whole bake input as a bake does.mnavQuery_FindHierarchicalPath takes a const
mnavHierarchy*. Any number of contexts may search one hierarchy at
once, as they search a navmesh, while no build or update runs on it
and no commit on the navmesh.
(#198)mnavQueryLimits.transitions: 16,384 by default, 0 to
MNAV_MAX_HIERARCHY_TRANSITIONS.mnav_errorCapacity. A host whose hierarchies have more transitions
raises the limit.mnavNavFlow.
(#199)| Old | New |
|---|---|
mnavFlowField |
mnavGridFlow |
mnavFlowFieldDef, mnavDefaultFlowFieldDef |
mnavGridFlowDef, mnavDefaultGridFlowDef |
MNAV_FLOW_FIELD_DEF_COOKIE |
MNAV_GRID_FLOW_DEF_COOKIE |
mnavCreateFlowField, mnavDestroyFlowField |
mnavCreateGridFlow, mnavDestroyGridFlow |
mnavFlowField_Begin, _Continue, _Update, _Build, _GetFlow, _Debug, _GetMisuse |
mnavGridFlow_Begin, _Continue, _Update, _Build, _GetFlow, _Debug, _GetMisuse |
mnavFlow |
mnavCellFlow |
MNAV_MAX_FLOW_CELLS |
MNAV_MAX_GRID_FLOW_CELLS |
MNAV_MAX_NAVFLOW_POLYGONS, _TILES, _LINKS |
MNAV_MAX_NAV_FLOW_POLYGONS, _TILES, _LINKS |
mnav_errorBusy writes none of its
outputs: they stay as they were, where 0.3.0 zeroed them. Only a call
back in from host code the object runs can be refused as busy: an
allocator, or a link generation's clearance test. An output may be one
the call in progress is filling.
(#197,
#196)mnavQuery_CheckReachable and mnavQuery_GenerateLinks;mnavGridFlow_Continue and mnavNavFlow_Continue;mnavHierarchy_Build and mnavHierarchy_Update;mnavAvoidance_Avoid and mnavAvoidance_Avoid3D, whose
velocities stay as given.mnavStageLink gives is a creation's: the null id on
any failure, busy included.mnavFlightVolume_FindNearestPoint zeroes nearestOut
when no open point lies within the radius, as the other "not found"
answers do. Before, it left the query point there.
(#190)docs/user/) uses the new defs, names and report
fields.The whole API takes the Maul family's naming rule, so most functions have new names and 25 take their arguments in a new order (the table under Changed). Avoidance velocities change: they are binary32 now, a velocity held to the maximum speed no longer passes it, and an agent that only its own speed holds back no longer steps aside. Tile bytes, fingerprints and paths do not change, and no tile format rises: tiles baked by 0.2.0 load as they are.
mnavLink_IsEnabled(navmesh, link, enabledOut) reads whether a link
is switched on, as committed: right after mnavLink_StageEnable it
still gives the old state, and the new one after
mnavNavmesh_Commit. A link staged and not yet committed is
mnav_errorState, as with mnavLink_GetState.
(#181)mnavObject_Verb: the object is the kind
of the first id the call acts on (mnavPolygon_GetArea,
mnavLink_StageEnable), or else the object it takes first
(mnavNavmesh_Commit, mnavQuery_FindPath). Each object's misuse
count is mnav<Object>_GetMisuse.mnavResetCorridor, mnavSetCorridor,
mnavSteer), mnavGetVersion and mnavHash64 keep their names.
mnavResultName is mnavGetResultName.mnavClearanceFn is mnavClearanceFunction, a function type, and
mnavLinkGenDef.clear is mnavClearanceFunction* clearance.mnavSteerDef.anticipateTurns is enableTurnAnticipation, and
mnavFlightDef.groundBelow is enableGroundFill.| Old | New | Parameters |
|---|---|---|
mnavResultName |
mnavGetResultName |
|
mnavGetAvoidanceMisuse |
mnavAvoidance_GetMisuse |
|
mnavAvoid |
mnavAvoidance_Avoid |
|
mnavAvoid3D |
mnavAvoidance_Avoid3D |
|
mnavDebugAvoidance |
mnavAvoidance_Debug |
|
mnavDebugAvoidance3D |
mnavAvoidance_Debug3D |
|
mnavGetBakerMisuse |
mnavBaker_GetMisuse |
|
mnavBakeTile |
mnavBaker_BakeTile |
|
mnavBakeTile2D |
mnavBaker_BakeTile2D |
|
mnavCopyBakedTile |
mnavBaker_CopyTile |
|
mnavBakeTileCached |
mnavBaker_BakeTileCached |
|
mnavRebuildTile |
mnavBaker_RebuildTile |
|
mnavGetTileIndexMisuse |
mnavTileIndex_GetMisuse |
|
mnavGetTileCacheMisuse |
mnavTileCache_GetMisuse |
|
mnavDropCachedTile |
mnavTileCache_DropTile |
|
mnavGetTileCacheBytes |
mnavTileCache_GetBytes |
|
mnavDebugNavmesh |
mnavNavmesh_Debug |
|
mnavDebugLinks |
mnavNavmesh_DebugLinks |
|
mnavDebugCorridor |
mnavNavmesh_DebugCorridor |
|
mnavGetFlightBakerMisuse |
mnavFlightBaker_GetMisuse |
|
mnavBakeFlightTile |
mnavFlightBaker_BakeTile |
|
mnavCopyFlightTile |
mnavFlightBaker_CopyTile |
|
mnavGetFlightVolumeMisuse |
mnavFlightVolume_GetMisuse |
|
mnavStageFlightTile |
mnavFlightVolume_StageTile |
|
mnavStageFlightTileRemoval |
mnavFlightVolume_StageTileRemoval |
|
mnavCommitFlight |
mnavFlightVolume_Commit |
|
mnavGetFlightTile |
mnavFlightVolume_GetTile |
|
mnavIsFlightOpen |
mnavFlightVolume_IsOpen |
|
mnavFlightRaycast |
mnavFlightVolume_Raycast |
|
mnavCheckFlightPath |
mnavFlightVolume_CheckPath |
|
mnavFindNearestFlightPoint |
mnavFlightVolume_FindNearestPoint |
|
mnavDebugFlight |
mnavFlightVolume_Debug |
|
mnavFindFlightPath |
mnavQuery_FindFlightPath |
|
mnavBeginFlightPath |
mnavQuery_BeginFlightPath |
|
mnavContinueFlightPath |
mnavQuery_ContinueFlightPath |
|
mnavFinishFlightPath |
mnavQuery_FinishFlightPath |
|
mnavGetFlowFieldMisuse |
mnavFlowField_GetMisuse |
|
mnavBeginFlowField |
mnavFlowField_Begin |
(field, grid, region, goals, goalCount, filter) |
mnavContinueFlowField |
mnavFlowField_Continue |
|
mnavUpdateFlowField |
mnavFlowField_Update |
|
mnavBuildFlowField |
mnavFlowField_Build |
(field, grid, goals, goalCount, filter) |
mnavFlowAt |
mnavFlowField_GetFlow |
|
mnavDebugFlowField |
mnavFlowField_Debug |
|
mnavGetHierarchyMisuse |
mnavHierarchy_GetMisuse |
|
mnavBuildHierarchy |
mnavHierarchy_Build |
|
mnavUpdateHierarchy |
mnavHierarchy_Update |
|
mnavFindHierarchicalPath |
mnavQuery_FindHierarchicalPath |
|
mnavGenerateLinks |
mnavQuery_GenerateLinks |
(query, navmesh, def, tiles, filter, linksOut, capacity, countOut) |
mnavClearanceFn |
mnavClearanceFunction |
a function type (see above) |
mnavGetNavFlowMisuse |
mnavNavFlow_GetMisuse |
|
mnavBeginNavFlow |
mnavNavFlow_Begin |
(field, navmesh, region, goals, goalCount, filter) |
mnavContinueNavFlow |
mnavNavFlow_Continue |
|
mnavBuildNavFlow |
mnavNavFlow_Build |
(field, navmesh, goals, goalCount, filter) |
mnavNavFlowAt |
mnavNavFlow_GetFlow |
|
mnavDebugNavFlow |
mnavNavFlow_Debug |
|
mnavGetNavmeshMisuse |
mnavNavmesh_GetMisuse |
|
mnavStageTile |
mnavNavmesh_StageTile |
|
mnavStageTileRemoval |
mnavNavmesh_StageTileRemoval |
|
mnavCommit |
mnavNavmesh_Commit |
|
mnavGetTier |
mnavNavmesh_GetTier |
|
mnavGetTile |
mnavNavmesh_GetTile |
|
mnavStageArea |
mnavPolygon_StageArea |
|
mnavGetArea |
mnavPolygon_GetArea |
|
mnavStageLinkEnabled |
mnavLink_StageEnable |
|
mnavGetLink |
mnavLink_GetState |
|
mnavGetQueryMisuse |
mnavQuery_GetMisuse |
|
mnavFindPolygons |
mnavNavmesh_FindPolygons |
(navmesh, center, halfExtents, filter, polygonsOut, capacity, foundOut) |
mnavFindNearest |
mnavNavmesh_FindNearest |
(navmesh, point, halfExtents, filter, nearestOut) |
mnavFindRandomPoint |
mnavNavmesh_FindRandomPoint |
(navmesh, seed, filter, pointOut) |
mnavCheckCorridor |
mnavNavmesh_CheckCorridor |
(navmesh, corridor, filter, validOut) |
mnavGetHeight |
mnavPolygon_GetHeight |
|
mnavFindPath |
mnavQuery_FindPath |
(query, navmesh, startPolygon, start, endPolygon, end, filter, pathOut) |
mnavFindShortestPath |
mnavQuery_FindShortestPath |
(query, navmesh, startPolygon, start, endPolygon, end, filter, pathOut) |
mnavBeginPath |
mnavQuery_BeginPath |
(query, navmesh, startPolygon, start, endPolygon, end, filter) |
mnavContinuePath |
mnavQuery_ContinuePath |
|
mnavFinishPath |
mnavQuery_FinishPath |
|
mnavMoveAlongSurface |
mnavQuery_MoveAlongSurface |
(query, navmesh, startPolygon, start, end, filter, moveOut) |
mnavCorridorCorners |
mnavQuery_FindCorridorCorners |
(query, corridor, navmesh, cornersOut) |
mnavCorridorAreas |
mnavQuery_FindCorridorAreas |
(query, corridor, navmesh, cornersOut, runsOut, capacity, countOut) |
mnavMoveCorridor |
mnavQuery_MoveCorridor |
(query, corridor, navmesh, wanted, filter, moveOut) |
mnavMoveCorridorTarget |
mnavQuery_MoveCorridorTarget |
(query, corridor, navmesh, wanted, filter, moveOut) |
mnavShortcutCorridor |
mnavQuery_ShortcutCorridor |
(query, corridor, navmesh, toward, filter, shortenedOut) |
mnavReplanCorridor |
mnavQuery_ReplanCorridor |
(query, corridor, navmesh, halfExtents, filter, pathOut) |
mnavFindGridPath |
mnavQuery_FindGridPath |
(query, grid, start, end, filter, pathOut) |
mnavFindWallDistance |
mnavQuery_FindWallDistance |
(query, navmesh, polygon, center, radius, filter, nearestOut) |
mnavFindWalls |
mnavQuery_FindWalls |
(query, navmesh, polygon, center, radius, filter, wallsOut, capacity, foundOut) |
mnavFindRandomPointAround |
mnavQuery_FindRandomPointAround |
(query, navmesh, polygon, center, radius, seed, filter, pointOut) |
mnavCheckReachable |
mnavQuery_CheckReachable |
(query, navmesh, startPolygon, start, endPolygon, end, filter, endOut) |
mnavRaycast |
mnavQuery_Raycast |
(query, navmesh, startPolygon, start, end, filter, rayOut) |
mnavAgent and mnavObstacle take velocity and preferred as
mnavVec2, and mnavAvoidance_Avoid writes mnavVec2;
mnavAgent3D and mnavSphere take mnavVec3, and
mnavAvoidance_Avoid3D writes mnavVec3.mnavSteering.velocity and mnavWall.normal are mnavVec3, and
mnavRay's normalX and normalZ are one mnavVec3 normal.mnavVec2, mnavVec3, mnavPos2 and mnavPos3 are all in
base.h.mnavSteer rounds its velocity to binary32 too.
(#179)mnavPolygon_GetHeight, mnavFlowField_GetFlow,
mnavNavFlow_GetFlow and mnavQuery_FindFlightPath left as they
were on mnav_errorOutside are now zeroed, and so are
mnavAvoidance_Avoid's and mnavAvoidance_Avoid3D's velocities when
the set's limit holds the agents.
(#168)mnavWallSegment is removed. mnavQuery_FindWalls fills
mnavWall { start, end, point, normal, distance }, which gains the
point nearest the center.mnavQuery_FindWallDistance fills an
mnavNearestWall { found, limited, wall }, whose wall is, field
for field, the first one mnavQuery_FindWalls lists. Its normal is
the wall edge's normal toward the walkable side; it used to be the
direction from the wall's point to the center, which differs at a
corner and is (center - point) / distance. With no wall found,
the wall is zeroed instead of holding the radius and the center.mnavNavmesh_Debug and mnavQuery_GenerateLinks take a
const mnavTileRange* (NULL for every tile) instead of four tile
coordinates, and mnavTileRange { x0, z0, x1, z1 } replaces
mnavNavFlowRegion.mnavCellRange { x0, y0, x1, y1 } replaces
mnavFlowRegion { x, y, width, height }. Both corners of either
range are included, so a region of no cells is a backward range.mnavBaker_CopyTile and mnavFlightBaker_CopyTile
refuse a baker that holds no tile (before its first bake, or after a
failed one) with mnav_errorState, not mnav_errorInvalid, and
count no misuse for it.
(#167)docs/user/) uses the new names, types and argument
orders, and the troubleshooting page says what a failed call leaves
in its outputs.samples/flight.c) no longer leaves fliers
pressed against a pillar when their speed changes slightly: a flier
moves on to the next route point only once it can see it, and
searches its route again when it loses sight of it.
(#175)Tile bytes, fingerprints, paths and velocities do not change, and no tile format rises: tiles baked by 0.1.0 load as they are. Flow fields change for one call sequence (see Fixed).
mnavGetNavmeshMisuse,
mnavGetQueryMisuse, mnavGetBakerMisuse, mnavGetTileCacheMisuse,
mnavGetTileIndexMisuse, mnavGetHierarchyMisuse,
mnavGetFlowFieldMisuse, mnavGetNavFlowMisuse,
mnavGetAvoidanceMisuse, mnavGetFlightBakerMisuse and
mnavGetFlightVolumeMisuse. A count rises for each call refused with
mnav_errorInvalid or mnav_errorBusy, so a release build can catch
a host's bugs.
(#141,
#145,
#148)mnav_errorInvalid -1, mnav_errorCapacity -2, mnav_errorStale -3,
mnav_errorUnsupported -4, mnav_errorState -6, mnav_errorVersion
-7, mnav_errorFormat -8, mnav_errorLimit -9, mnav_errorBusy -10,
and maul-nav's own mnav_errorNotLoaded -32 and mnav_errorOutside
-33. A host that stored or compared the numbers compares the names.
Some calls refuse with a different result:mnavBakeLimits and mnavFlightLimits included, is
mnav_errorCapacity; it was mnav_errorLimit.mnav_errorRange is removed. A coordinate past the extent is
mnav_errorLimit, as is any value past a published MNAV_MAX_* or
MNAV_MIN_* bound. MNAV_MAX_PIECE_CORNERS,
MNAV_MAX_CLIP_CORNERS, MNAV_MAX_INDEX_ENTRIES and
MNAV_MAX_FLIGHT_VOXELS are new public bounds.mnav_errorFormat.mnav_errorState.mnav_errorInvalid. An infinity is mnav_errorLimit past
a published bound, and mnav_errorInvalid elsewhere.mnavIsFlightOpen refuses a point more than 2^28 voxels from the
origin, as the other flight calls do; it took up to 2^30.(#135)
- Breaking: mnav_errorTier is removed. A staged tile, area change
or link toggle that the navmesh's tier does not allow is refused with
mnav_errorUnsupported.
(#138)
- Breaking: host code may not call into the objects of a running
call. That is an allocator, a baker's clock or a link generation's
clearance test. Such a call is refused with mnav_errorBusy when it
returns a status, does nothing when it returns nothing, and counts one
misuse. This holds for the object the host code serves and for the
other objects the running call uses: the baker, tile index and tile
cache of a bake or rebuild, and the context and navmesh of a
hierarchy's build or update. It also holds for the release of an
object's own memory. A clearance test or a hierarchy's allocator may
still call mnavStageTile and mnavStageTileRemoval. Before, such a
call could read freed memory.
(#141,
#145,
#147)
- Breaking: a call refused with mnav_errorInvalid counts one
misuse on the first object it is given. Input geometry a bake refuses
and its report names counts none.
(#148)
- Breaking: a place outside what an object covers is
mnav_errorOutside, not mnav_errorInvalid, and counts no misuse.
This covers:
- mnavGetHeight for a point off the polygon
- mnavFlowAt and mnavNavFlowAt for a cell or polygon outside the
field's region
- mnavIsFlightOpen, mnavFindFlightPath and mnavBeginFlightPath
for a point below or above the flight volume
A host that handled these as mnav_errorInvalid handles
mnav_errorOutside. The outputs stay as they were, but
mnavIsFlightOpen sets openOut to false.
(#148,
#150)
- The troubleshooting table lists the new numbering and results. The
getting-started and baking pages say what host code may call.
mnavBeginFlowField cut an
earlier repair short now matches a fresh build, as
mnavUpdateFlowField promises. Before, cells the earlier repair had
marked could keep their old costs and next cells. Flow fields change
for that sequence only.
(#130)mnavStageLink refuses a link with mnav_errorLimit when a crossing
would take a link slot its attachment key cannot hold. This can happen
at MNAV_MAX_LINKS links once a slot has worn out. Before, the link
took a slot that wrapped to slot 0, and a search crossed the wrong
link or read out of bounds.
(#122)MNAV, format
version, generation, fingerprint, the payload's hash and size, and the
field count) followed by tagged fields in name order: DPRT, DTRI,
DVRT, POLY, TILE and VERT. Bytes nothing read are gone: the
stored header size, reserved and pad words, the element counts, which
follow from the fields' lengths, and each detail triangle's outline
bits, with mnavDetailTriangle.outline. The loader refuses a field
that is repeated, out of order, empty, not a whole number of records,
or padded with non-zero bytes, and bytes after the last field, with
mnav_errorInvalid naming the field's mnavTileSection; an unknown
tag is mnav_errorVersion. MNAV_TILE_FORMAT is 3. Every tile's
bytes and fingerprint change, so a host rebakes its tiles; the meshes
they hold, and so paths and queries, do not change.
(#97)MNVF, then the fields FLHT, LEAF, NODE and ROOT,
refused as tiles are. ROOT must hold the def's cube count and FLHT
exactly 56 bytes, and NODE and LEAF are checked against the def's
limits before anything is allocated. MNAV_FLIGHT_FORMAT is 3 and
MNAV_FLIGHT_GENERATOR 2. Every flight tile's bytes and fingerprint
change; flight queries do not.
(#98)mnavBakeTile and
mnavBakeTile2D now take an input record, const mnavBakeInput* and
const mnavBake2DInput*, and the forms that took meshes or outlines
alone are removed, as are the names mnavBakeTileInput and
mnavBakeTile2DInput. A call that passed meshes alone passes
&(mnavBakeInput){meshes, count, NULL, 0, NULL, 0, NULL}. Results do
not change.
(#95)mnavBakeDef.maxEdgeError's documentation says that walls simplified
a cell or more can cross, that a ring which then does not triangulate
whole loses the area it did not triangulate, and that
mnavBakeReport.partialRings counts it.
(#91)mnavBakeReport.partialRings counts the polygon stage's rings alone:
a detail outline, a simple ring since #109, always triangulates whole.
(#112)mnavGenerateLinks refuses a spacing below the
navmesh's cell size with mnav_errorInvalid. A spacing small enough
used to make an out-of-range conversion of each edge's sample count.
Generation now stops with mnav_errorLimit when a landing's search
box meets more than MNAV_MAX_LINK_LANDINGS (32) polygons, which used
to drop that link without a word, or at a link past MNAV_MAX_LINKS.
On a stop, countOut gives the links found so far and the buffer
holds the first of them. Links for a spacing of a cell or more do not
change.
(#116)mnavFindRandomPointAround returns mnav_errorLimit
when a polygon clipped to its circle would have more corners than the
clip holds. Rounding near a cut could add one corner too many, and the
clip wrote past its buffer. Results otherwise do not change.
(#113)partialRings. Polygons sharing an edge
still place the same points. Tile bytes and fingerprints change for
polygons with sloped edges, and MNAV_BAKE_GENERATOR is 3, so a host
rebakes its tiles.
(#109)mnav_errorLimit instead of writing past the
piece. Rounding of an interpolated corner near a cell line could make
a cut add more corners than exact arithmetic allows. No known bake
reaches it, and every tile is as it was.
(#115)mnavCorridor refuses one that is not well
formed, with mnav_errorInvalid, before reading its buffer: a
corridor has a buffer, a capacity of at least 1, and from 1 to
capacity polygons. A count past the capacity used to make the calls
read past the caller's buffer. mnavSetCorridor refuses only a
capacity below 1.
(#114)mnavRebuildTile compares a cached tile's bake settings in full, not
by a 64-bit hash, so a baker of another def is always refused with
mnav_errorInvalid. A cache's tile slots grow by 80 bytes each.
(#90)MNAV_BAKE_GENERATOR does not change.
(#25)mnav_pathNone and the start alone as its path. This applies
when the space is found closed within 512 blocks and the node budget.
Before, the search flooded its whole node budget and returned
mnav_pathOutOfNodes with a partial path toward the outside, which
could never reach the end.
(#22)The first release: navmesh and flight volume baking, queries, corridors, flow fields and avoidance, with results that are bit-identical on every platform, compiler and worker count.
clang-cl,
and WebAssembly.mnav_errorVersion.mnavQueryFilter and
mnavLinkGenDef lose their version field, and only the root defs
carry MNAV_ABI_VERSION, which holds the whole release before 1.0. A
program built against 1.x headers is refused with mnav_errorVersion
and must be rebuilt.