Skip to content

ntre_bullet_tdm: navmesh rework - #155

Merged
sunzenshen merged 3 commits into
NeotokyoRebuild:masterfrom
sunzenshen:navmesh-bullet-release
Oct 14, 2026
Merged

sunzenshen merged 3 commits into
NeotokyoRebuild:masterfrom
sunzenshen:navmesh-bullet-release

Conversation

@sunzenshen

@sunzenshen sunzenshen commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

ntre_bullet_tdm: navmesh rework

One file, neo/maps/nav/ntre_bullet_tdm.nav. The NAV_MESH_PRECISE + NAV_MESH_CLIFF marks use the movement rules of NeotokyoRebuild/neo#2168 (merged).

Dependencies and status

Needs (worse than master, or broken, without it):

  • Bots hold an exact move direction on PRECISE areas neo#2175 ("Bots hold an exact move direction on PRECISE areas", ready for review), for the train seats: the aisle line of each car is marked PRECISE (see "3. Train seats"). With it, bots get stuck on the seats 0.9 times a match on this mesh against 3.7 on master; on upstream code without it, 5.8 against 3.9 (see "How it was tested").

The rest of the gain needs no code change. Commits 1-2 were measured with and without the draft NeotokyoRebuild/neo#2176 (then only its unwanted-ladder release, now its changes 1 and 7), and their gain does not depend on it; the map's four nav ladders are master's.

Helped by (measured better with it; the mesh does not wait on it):

  • None measured.

Pending before review:

At a glance

master this PR
nav areas 271 220
file size 78,998 bytes 63,185 bytes (-20 %)
areas not linked to the rest of the mesh 3 0
areas the engine blocks at every round start 0 0
areas marked PRECISE + CLIFF 0 12
areas marked PRECISE (train aisles) 0 17
nav ladders 4 4 (records unchanged)
bot stuck events a match (see below) 125 7
of which on the train seats 3.7 0.9

Three commits:

  1. Rework - the mesh itself.
  2. Id alignment with master - ids only, so an id-keyed diff against master reads sensibly.
  3. Train seats - keeps bots off the seats in the three train cars.

1. What changed

  • The train doorways. Each of the four doorways is narrower than the areas either side share: a player hull swept through one clears 2 of 13 lanes, and the path's crossing point usually landed on a blocked lane against the door frame. An 8 u area now spans each doorway through its clear lanes and links to both sides, in place of the direct links. On master about 90 % of the stuck events below sit at the doorways, mostly bots pressing into one another there; on this mesh about 3 a match do.
  • Sliver areas are merged into their neighbors on the same floor (39 of master's areas). Two places keep master's splits, because merging joined a cul-de-sac to a walkway and made bots stop there:
    • Shaft 1's foot. Master has ladder 1's foot (1025, a cul-de-sac at the bottom of the shaft) and the corridor beside it (1026) as two areas. Merged, the corridor became the ladder's bottom area. Bots going down the shaft use the drop links from the deck, and the drop point landed beside the ladder, which caught them. Ladder 1's shaft became the map's top stuck spot, about 45 events a match. With the two areas split as on master, it is gone from the hotspots.
    • The west car's seats (1027 / 1028, 1071 / 1072 and three more pairs). Merged, bots stuck there about once a match more than on master.
  • Fall edges. The whole track side of the map is a trigger_hurt over the track floor, and every upper-level area on that side drops into it. 12 areas are marked PRECISE + CLIFF, where test bots fell: the deck edge strips beside each shaft, ladder 1's top landing and the west roof's edge, and a 50 u strip split off the track side of two more roofs. Marking only the edge strip of a roof keeps the rest of it a normal walkway.
  • Ladders 1 and 4 are no longer descended from their forward top. These two ladders stand in shafts next to the spawns, and the forward top landing lies behind the ladder's plane. A descent started there has to walk round to the ladder's face; the bot usually mounts it standing on the landing and is pushed back off. On master, 63 % of the descents started there end back at the top, about 5 a match on ladder 1 and 3 on ladder 4 (32 matches, upstream master + #2176). These two landings no longer list the ladder going down. They stay the ladder records' exit at the top, so climbing up works as before (climbs a match, master against this mesh: ladder 1 27 / 30, ladder 4 18 / 22). Bots go down by the drop links into the shafts, which work now that shaft 1's foot is split. The side landings still list the ladders going down. Every ladder end is still connected. Descents fail the same way from the side landings and from the forward tops of ladders 2 and 3, but those are rare (under 0.4 a match each), so they are left as they are.
  • 3 small crouch areas linked to nothing are removed (25 u squares on the lower level, no link in or out). On master, bots standing on the seats there resolve to them and cannot plan a path: about 1 FAIL_NO_PATH_EXISTS a match.
  • Re-analyzed in game after the edits, so the per-area visibility lists bots use for what they can see are current.

2. Id alignment

229 of the 233 areas carry the id of the master area they match. No kept id sits more than 64 u from its master location. An id-keyed diff shows 4 added areas (two of the doorway strips and the two roof edge strips) and 42 removed (39 merged into a neighbor, the 3 unlinked ones). Geometry, connections, attributes and the analysis data are unchanged by this step.

3. Train seats

Bots are not meant to stand on the train seats, so this commit keeps them on the aisle. Before it, on master and after commits 1-2 alike, bots got onto a seat 45 to 55 times a match. Mostly this happened while cutting the turn from a car's doorway into its aisle: the hull met a seat's aisle-side armrest and the path follower's ledge climb jumped onto it. Bots also stepped onto a cushion while side-stepping one another or strafing in a fight. A bot on an aisle-side armrest cannot step down into the aisle, because its head meets the light strip over the aisle, so it stays there until it gives up its path.

  • 11 seat-front areas and 3 table and seat tops are removed. Each seat-front area was a 25 u square whose far side lay on a seat cushion, 18 u up; the other three sat on a table and the seat beside it in the middle car, 33 u up, linked from the aisle. All were side pockets: every other area keeps its links and its reachability. Their links into the aisle strips also pulled the aisle's path points 8 u toward the seats.
  • The aisle line of each car is marked PRECISE (17 areas): the doorway strip at the car's west end and the 25 u aisle strips between the seat rows. The west car's vestibule is split so the line runs on through it as a 25 u strip. On a PRECISE area the path follower does not skip ahead past path points, and bots do not side-step one another, strafe in a fight or super-jump. With #2175 they also move in the exact direction of their path instead of on the nearest of eight movement keys. Without it, a bot that looks around while walking the aisle still drifts up to 30 degrees off its path and into an armrest, which is why the seats need #2175.
  • The leg room between the seat rows is left unmarked, so bots still pass one another and fight there.
  • Re-analyzed in game. 215 of the 220 areas carry master ids: the vestibule strip (1152) is the one added area, and 14 more master areas are removed.

How it was tested

  • Reachability:
    • every spawn can reach every other spawn
    • every area is reachable from a spawn
    • no area is blocked at round start
  • Master against this mesh, same bot code. Byte-identical copies of the map, one carrying each .nav, run back to back. Upstream master plus #2175, #2176 and #2186, with harness logging added. TDM, one 5-minute round, 30 bots, default weapon damage, 32 matches a mesh, 8 at a time. The stuck count is OnStuck plus FAIL_STUCK move failures, excluding the spawn crush at round start and the weapon-scavenging behavior.
    • stuck events 125.0 -> 6.9 a match (paired x0.05, 95 % interval [0.04, 0.07], 32 of 32 pairs down)
    • of those, with the bot on a train seat: 3.7 -> 0.9 a match (x0.24 [0.07, 0.55], 22 pairs down, 4 up; in 25 of 32 matches -> 7); bots getting onto a seat 45 -> 8 times a match
    • FAIL_NO_PATH_EXISTS move failures 4.9 -> 8.6 a match (x1.45 [0.90, 2.34]); almost all are a bot chasing an enemy that will not plan through a fresh grenade's hazard in the corridors between the cars, which ends at the hazard by design
    • "fell off the path" failures 5.0 -> 5.8 a match (x1.14 [0.79, 1.62])
    • kills 201.2 -> 198.2 a match (x0.98 [0.97, 1.00])
    • team kill ratio (Jinrai / NSF enemy kills) 0.84 -> 0.93
  • Without #2175 (upstream master plus #2176 and #2186), 32 pairs: stuck events 133.0 -> 18.7 a match (x0.14 [0.11, 0.19], 32 of 32 down), but on the seats 3.9 -> 5.8 (x1.47 [1.02, 2.06]). Fewer bots get onto a seat (43 -> 25 a match), but those that drift along the aisle into an armrest stay longer.
  • Commits 1-2 alone (before the seat commit), master against them with #2176: 32 pairs x0.13 [0.11, 0.17], 32 of 32 down (135.0 -> 18.7 a match); with #2176's behavior switched off (upstream ladder code), 16 pairs x0.11 [0.08, 0.14], 16 of 16 down. Earlier variants without ladder 2's forward-top descent: every pair down in three more batches.
  • Fall deaths. Master 7 in 96 matches, this mesh 9 in 96 over the batches with the seat commit; commit 3 changes nothing on the upper level they start from (ladder tops and the marked deck edges). Over every batch of this upper level, master 0.12 a match (22 in 184), this mesh 0.12 (36 in 296). Most of this mesh's start at a ladder top or on a marked strip: the bot walks along it looking elsewhere, and the nearest of its eight movement keys points a little toward the drop. That is a bot movement matter, not the mesh.
  • Bots still see and shoot across the mesh. 82 % of kills are between bots in different nav areas and 66 % in non-adjacent ones, against 84 % / 61 % on master (kill distance median 196 u against 193 u).

No ladder was added or changed, so no ladder probes were run.

Known, not changed

  • Ladder 4's shaft. Bots dropping into it from the deck often fall past the drop point, and the path follower reports "fell off the path" and plans again from the floor. Same on master.
  • Doorway crowding. The doorway strips still see bots blocking one another, about 3 events a match against master's 120.

One file. Against master: 271 -> 233 areas, 78,998 -> 67,030 bytes;
3 areas not linked to the rest of the mesh -> 0; 0 areas blocked at
round start in either.

- The four train doorways are narrower than the areas either side
  share: a player hull clears 2 of 13 lanes through each. An 8 u area
  now spans each doorway through its clear lanes, linked to both
  sides, in place of the direct links. On master the doorways hold
  about 85 % of the map's stuck events.
- Sliver areas are merged into their neighbors on the same floor (39
  of master's areas), except where a merge would join a cul-de-sac to
  a walkway: shaft 1's foot and the west car's seats keep master's
  splits.
- 12 areas beside the lethal track floor are PRECISE + CLIFF: the deck
  edge strips beside each shaft and a 50 u strip along the track side
  of two roofs.
- The landing behind the ladder plane at the top of ladders 1 and 4
  no longer lists the ladder going down; it stays the exit of a
  climb. Descents started there mostly end back at the top, about 5
  and 3 times a match on master. Bots go down by the drop links into
  the shafts.
- 3 small crouch areas linked to nothing are removed.
- Re-analyzed in game after the edits.
Renumbers area ids only, so an id-keyed diff against master reads
sensibly: 229 of the 233 areas carry the id of the master area they
match (224 before), no kept id sits more than 64 u from its master
location, and the diff shows 4 added / 42 removed areas (39 of the 42
merged into a neighbor on the same floor, 3 pruned). Geometry,
connections, attributes and the analyzed visibility data are unchanged
(verified topology-identical).
The seats in the three train cars are not places for bots to stand.
Bots stepped or jumped onto them while cutting the turn into a car's
aisle or side-stepping in it. A bot left on an aisle-side armrest
cannot step down, because its head meets the light strip over the
aisle, and stays stuck there.

- Remove the 11 areas whose raised side lies on a seat cushion and
  the 3 table and seat tops in the middle car. All were side pockets:
  every other area keeps its links and reachability.
- Mark each car's aisle line PRECISE: the doorway strip at the car's
  west end and the 25 u aisle strips between the seat rows. The west
  car's vestibule is split so the line runs through it as a strip.
  On a PRECISE area the path follower does not skip ahead and bots do
  not side-step, strafe or super-jump; with neo#2175 they also move
  in the exact direction of the path.
- Re-analyzed in game. Existing areas keep their ids; the vestibule
  strip is the one added area.

Seat stuck events a match, master -> this mesh, 32 matches each on
upstream with neo#2175, neo#2176 and neo#2186: 3.7 -> 0.9. The PRECISE
line needs neo#2175; without it the seats measure 3.9 -> 5.8.
@sunzenshen

sunzenshen commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor Author

A number of the gains were through encouraging the bots to take the narrow connection between the passageways to discourage getting stuck in the portal frames:

image

This navmesh needs the Precise annotation to reduce falls off the side of the train:

image

One known issue is that bots are discouraged to cross the roof ever since NeotokyoRebuild/neo#1601 was introduced. Before, bots were able to cross the roof, but at the moment bots rarely take that path anymore.

@sunzenshen
sunzenshen marked this pull request as ready for review October 9, 2026 04:26
@sunzenshen
sunzenshen requested a review from sunmachine October 9, 2026 04:26

@sunmachine sunmachine left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Precision navmeshes work great with the code changes on top.

@sunmachine
sunmachine requested a review from a team October 14, 2026 02:27
@sunzenshen
sunzenshen merged commit c947492 into NeotokyoRebuild:master Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants