Repository navigation
ntre_engage_ctg: navmesh rework - #152
Merged
sunzenshen merged 7 commits intoOct 14, 2026
Merged
Conversation
One file. Against master: 1950 -> 1443 areas, 3,343,660 -> 1,911,403 bytes; areas the engine blocks at every round start 22 -> 0; areas no spawn can reach 110 -> 63. - Sliver areas merged into their neighbors on the same floor, props carved out of standing room, and areas the engine blocks at round start (a prop or brush over their center) cut away. - Walk links a player hull cannot cross are cut: past the truck near (0,1300), the wrecked mech near (850,1750) and the car near (1010,90). - The drop from the roof near (1350,275) to the street 250 u below (12598 -> 728) is cut. It was master's largest stuck spot: bots heading for it pressed into the roof's edge. - Ghost spawn 6's deck near (133,-145): its pocket had exits and no entry; a deck strip gives it one. - The balcony staircase from NeotokyoRebuild#135 is kept as merged. - Pockets no spawn can reach and nothing links into are removed. - Re-analyzed in game after the edits.
Renumbers area and ladder ids only, so an id-keyed diff against master reads sensibly: 1441 of the 1443 areas and both ladders carry the id of the master area they match, all of NeotokyoRebuild#135's staircase among them. Areas are matched only within 64 u of height. Geometry, connections, attributes and the analyzed visibility data are unchanged (verified topology-identical).
The walkway at z 144 west of the rooftop room (12598 / 12600 / 12610 / 12611, x 1250..1400, y 200..350) has 35 u parapets on its west, north and south sides. 12600 -> 1426 was a 252 u drop to the street over the north parapet: bots following it walked into the parapet. With NeotokyoRebuild#135's staircase it had become the shortest way off the roof. Cut; the walkway is left through the rooftop room and the staircase. Master's twin of it on the south side (12598 -> 728) was already cut. Ids unchanged. Re-analyzed in game after the edit.
NeotokyoRebuild#135 meshes each of the balcony staircase's four flights as six 5-6 u strips, one per 8 u tread, with gaps of up to 13 u between them and the landings. Each flight is now one sloped area from its lower landing's edge to its upper landing's edge, its low and high edges at the landings' heights, as nav_generate meshes a flight; the engine marks the four STAIRS at load. 24 areas become 4, each keeping its bottom step's id (12730, 12737, 12748, 12749). The landings, the railing-top strips and every link into or out of a flight are unchanged. Re-analyzed in game after the edit.
The middle and lower west landings each join two flights that run side by side, and the end of one flight's stringer stands up to 9 u over the landing at the inner corner of the turn. The links put the path's turn within half a hull of it, and bots turning there pressed into it. The upper west landing already turns 40 u clear. The middle landing (12588 / 12587) is split at x 1640 and its west halves are not linked to each other, so the turn is made east of x 1640. The lower west landing is split at x 1525: its east part beside flight A (new 12766) and 9572 beside flight B are not linked to each other and meet through 12723 west of x 1525; 9572 now spans flight B's full width, so a bot steps onto the flight at its middle. Re-analyzed in game after the edit.
An outside review of this mesh found walk links that run one way only, among them the reverse halves of the cuts at the wrecked mech, the car and the truck, and roof pockets entered only by climbs no bot plans. Each one-way pair was swept with a player hull in both directions by the engine's hull audit. - Finish the cuts at the wrecked mech (7031 / 11341, 7032 / 172), the car (7187 / 7185) and the truck (6251 / 2684): the hull is blocked both ways, and the reverse direction was still linked. - One-way links left by an earlier railing cut: cut both ways the seven pairs blocked both ways (interior stair handrails, a street lamp); restore the missing direction of eight pairs that are clear both ways, among them 7357 -> 843 beside the car and two panel vans. - Remove the ten climbs of 74-88 u that were the only way onto eight vehicle roofs and an awning (39 areas). No class plans a climb that high, so no route changes; the areas stay as drop-only pockets, like the other roof pockets in this mesh. Every area keeps its id. Re-analyzed in game (same graph, fresh visibility).
The engine's hull audit (a player hull stood on every area and swept across every link, in the server) of the previous revision, and navconnect's link check against master: - Restore the drop back of three climbs of 19-32 u whose drop had been cut: the climb reads clear on every lane. - Delete 12630, a 61 x 9 u strip on the wall trim beside the walkway stairs at (1322, 370): no hull stands on it, and its only way in was a 26 u climb blocked on every lane. - Delete areas no player hull stands in, every stand sample blocked: squares inside the spider tank, the taxi, the car by the parking meters, two street lamps, a scooter and a car, and two corner squares behind a wall at (1850, 630). - Cut six pairs blocked both ways that bots never cross: a parking meter, a scaffold strip, a stair handrail, the spider tank's legs, a vehicle barrier. Kept: the squares inside the wrecked mech near (838, 1750), which bots cross by jumping over its legs without sticking, and links the audit reads blocked on displacement slopes, which bots cross; the recycle bin near (2450, 812), a physics prop, left as at map load. Existing areas keep their ids. Re-analyzed in game (same graph, fresh visibility).
Contributor
Author
sunzenshen
marked this pull request as ready for review
October 9, 2026 05:26
sunmachine
approved these changes
Oct 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

ntre_engage_ctg: navmesh rework
One file,
neo/maps/nav/ntre_engage_ctg.nav. It was measured on upstream master plus the draft NeotokyoRebuild/neo#2176 (then only its unwanted-ladder release, now its changes 1 and 7) and NeotokyoRebuild/neo#2186 ("Bots skip weapons they cannot reach", merged since), with harness logging added. The balcony staircase from #135 is kept, with each flight of stairs made one area and its two lower turns widened (commits 4 and 5).ntre_disengage_ctgshares most of this layout and gets its own PR (#153).Dependencies and status
Needs (worse than master, or broken, without it):
Helped by (measured better with it; the mesh does not wait on it):
Pending before review:
At a glance
Seven commits:
1. What changed
2. Id alignment
1441 of the 1443 areas carry the id of the master area they match, including every area of the #135 staircase. Both ladders keep their ids. Areas are matched only within 64 u of height. Geometry, connections, attributes and the analysis data are unchanged by this step (verified topology-identical). After commits 4 and 5, 1421 of the 1426 areas carry master's ids; the other five are two areas of the rework and the three landing pieces of commit 5, numbered above master's highest id.
3. The roof walkway
With the staircase in place, bots reach the rooftop room (ghost spawn 2) both ways, and the north drop became the walkway's shortest way down. Measured against the same mesh without this cut (24 pairs): stuck events on the walkway, the room and ladder 2's top 11.8 -> 0 a match (0.47 -> 0 bot episodes a round; master 2.2 a match, 0.27 episodes a round). Bots leaving the room now walk down the staircase; commits 4 and 5 make that walk reliable.
4. One area per flight of stairs
#135 meshes each of the staircase's four flights as six strips, one per tread: 5-6 u deep on 8 u treads, flat, with gaps of 1-6 u between strips and up to 13 u between a flight and its landings.
nav_generatenever meshes stairs that way: it grows sloped areas over the ground samples that lie within 5 u of a plane, so a flight becomes one or a few areas, and the engine marks such an areaNAV_MESH_STAIRSwhen it loads the mesh (CNavArea::TestStairs). A flat strip never gets that mark, so the path follower handled the staircase as 24 separate steps, with uncovered gaps between them.Each flight is now one sloped area from its lower landing's edge to its upper landing's edge, level across the flight, its low edge at the lower landing's height and its high edge at the upper landing's: each meets its landings without a step. The plane stays within 13 u of every tread (the treads rise 10.3-11.7 u at a time). Each keeps its bottom step's id: 12730, 12737, 12748, 12749. The landings, the railing-top strips and every link into or out of a flight are unchanged; only the step-to-step links inside a flight are gone. The engine marks all four
STAIRSat load. 24 areas become 4.5. The staircase's two lower turns
The middle landing (z -9) and the lower west landing (z -85) each join two flights that run side by side. At the inner corner of each turn the end of one flight's stringer stands up to 9 u over the landing, and the links put the path's turn within half a hull of it: 12588 -> 12587 crosses at the landing's west edge, and 9572, the lower landing's south part, met flight B 8 u off the flight's middle. The few bots that still stalled after commit 4 stalled there. The upper west landing already turns 40 u clear of its stringers and had no stalls.
Stuck at the staircase: 0.012 bot episodes a round (master 0.044 in the same batches, commit 4 alone 0.038); none at the middle landing in 251 rounds. Against commit 4 alone, with and without #2176 (80 pairs): stuck events a match x1.00 [0.73, 1.38],
FAIL_NO_PATH_EXISTSfailures x0.82 [0.70, 0.95].6. Review fixes
Every area keeps its id.
How it was tested
BLOCKED_LINKS map=ntre_engage_ctg level_pairs=2510 oneway=0 keep=0 cut=0 area=3 check=4 entity=1)trigger_hurt; its twoenv_firedo 1 damage a second. No drop kills a bot at full health (the deepest drop link is 340 u, 9 damage). No fall marks were needed..nav, run back to back. CTG, 2 rounds of 3 minutes with the ghost pinned at each of the 8 ghost spawns in turn, 12 runs each (two batches of 6), 30 bots, default weapon damage, 8 matches at a time. Every match reached match end with 0 asserts and no crash (1127 matches on engage and disengage in all, probes and the other revisions included). The stuck count isOnStuckplusFAIL_STUCKmove failures, excluding the spawn crush at round start and the weapon-scavenging behavior.FAIL_NO_PATH_EXISTSmove failures 17.5 -> 15.0 a match (x0.86 [0.73, 1.00]); about three quarters of them on both meshes are bots attacking toward an area the bot code marks hazardous, which the path cost refuses; "fell off the path" failures 0.06 -> 0.02FAIL_NO_PATH_EXISTSmove failures 17.6 -> 16.1 a match; kills 48.8 -> 48.5 a match; ghost captures 8 of 64 rounds -> 6 of 67; 99 % of kills between different nav areas on both, 97 / 95 % between non-adjacent onesFAIL_NO_PATH_EXISTSmove failures 13.8 -> 16.7 a match: bots attacking toward an area the bot code marks hazardous, spread over the map, none toward a deleted area; kills 48.8 -> 49.2 a match; ghost captures 9 -> 10 of 96 rounds; 99 % of kills between different nav areas on both, 95 / 97 % between non-adjacent onesHow the pinned-ghost probes work
The offline checks show that the mesh links an area to a spawn. They do not show that a bot will walk there. To test one spot in game, the ghost is placed on it and bots are sent to get it.
sv_neo_ghost_spawn_pos "x y z", which replaces the position of the round's ghost spawn. The map file is not edited..bspunder a second name that loads its own.nav, so the same pin runs on both meshes in one batch.On this map
Both ends of both ladders were probed (every landing at ladder 1's top), plus the four landings of the #135 staircase, 3 matches each, 12 bots, at a tenth of weapon damage, on the same build, on this mesh before commit 3 (which only removes a drop off the roof); ladder 2's bottom got 6 more matches on each mesh, commit 3 included. Commits 4 and 5 leave the probed landings where they were (12587 and 12723 are split by commit 5, and both pieces stay linked to the mesh).
Bots rarely climb either ladder in normal play (0 to 0.5 climbs a match on both meshes). Ghost spawn 6 (see "Known, not changed") was probed the same way, 9 matches each: picked up in 8 of 9 on master and 6 of 9 here, always on the floor under the deck, after 90-580 s on both.
Known, not changed