Skip to content

Bots hold an exact move direction on PRECISE areas - #2175

Merged
sunzenshen merged 3 commits into
NeotokyoRebuild:masterfrom
sunzenshen:bot-nav-precise-move-direction
Oct 9, 2026
Merged

sunzenshen merged 3 commits into
NeotokyoRebuild:masterfrom
sunzenshen:bot-nav-precise-move-direction

Conversation

@sunzenshen

@sunzenshen sunzenshen commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Description

Bots hold an exact move direction on PRECISE areas

Bot movement presses the nearest of eight key combinations, up to 22.5 degrees off the goal. A bot looking somewhere other than where it walks, at a threat for example, drifts sideways by that much. On a narrow strip beside a fatal drop, which the per-map navmesh PRs mark NAV_MESH_PRECISE + NAV_MESH_CLIFF, that drift walks it off the edge.

On an area marked NAV_MESH_PRECISE or NAV_MESH_CLIFF, PlayerLocomotion::Approach() now hands the player the world direction to the goal (INextBotPlayerInput::SetMoveDirection(), #ifdef NEO). NextBotPlayer::PhysicsSimulate() applies it on every tick while the bot update that set it is still the latest one (GetTickLastUpdate()). Each tick it is converted against that tick's EyeAngles(), so a bot turning to aim keeps its line. The rest of the time the keys work as before.

In the air over a marked area, the held direction steers the bot's velocity rather than its facing. Air control only adds speed along the move direction (up to the air speed cap), so holding the direction to the goal does not stop sideways momentum, and a bot that climbs or drops onto a narrow ledge carries its run-up past the edge. While airborne, the direction handed to the player is the difference between the velocity toward the goal and the current velocity, so air control cancels the sideways speed. On the ground nothing changes.

Design by sunmachine, from their review of #2168. #2168 first used the stock SetButtonScale(), which falls short in two ways. Its 0.01 s timer lapses within a tick, and bot updates run every 6-13 ticks, so on most ticks the keys drove the bot anyway. And the scale is relative to the view at update time, so a bot that turned in between still drifted.

Navmesh PRs that rely on this

Reviewed and merged before these navmesh PRs:

  • ntre_ridgeline_ctg: navmesh rework and hillside ladder neoAssets#143 (ntre_ridgeline_ctg): the rail hop onto the east plateau (areas 17368 and 17369) is marked PRECISE. Bots climb onto a 3 u handrail top and drop to a crossbeam with 7-11 u of footing; the airborne steering keeps their climb momentum from carrying them off it (see "Narrow ledge" below).
  • ntre_bullet_tdm: navmesh rework neoAssets#155 (ntre_bullet_tdm): the aisle line of each train car is marked PRECISE. With this PR, bots get stuck on the seats 0.9 times a match on that mesh against 3.7 on master; without it, 5.8 against 3.9.

The other navmesh PRs that mark PRECISE + CLIFF fall edges (NeotokyoRebuild/neoAssets#138, #139, #146, #148, #149, #157 and #158) rely only on the merged #2168. On those edges this PR cuts falls further (see "Evidence"). NeotokyoRebuild/neoAssets#162, #163, #164, #165 and #166 also mark PRECISE areas and were measured only on a build that carries this PR.

Evidence

Measured on #2168's branch (the PRECISE waypoint and the no-sidestep rules) with harness logging added and a test-only switch, against the same build without any move-input change. Research navmeshes, 30 bots, default weapon damage, 8 wide, arms interleaved. 0 asserts in all 616 matches.

batch 1: 120 matches an arm (skyline, tarmac, redlight, ballistrade, bullet, apparatus) batch 2: 64 matches an arm (skyline, redlight, bullet, apparatus)
fall deaths x0.79 [0.64, 0.93] (502 -> 396) x0.69 [0.59, 0.77] (418 -> 290)
falls from PRECISE / CLIFF areas x0.75 [0.58, 0.93] x0.66 [0.51, 0.78]
stuck events on PRECISE / CLIFF areas x1.84 [1.34, 2.55] (265 -> 488) x1.42 [0.92, 2.27] (314 -> 447)
stuck events, whole match x1.01 [0.81, 1.26] x1.02 [0.82, 1.29]
kills x0.99 x1.00

The intervals are paired bootstraps over scenarios. Skyline carries most of the fall cut: 4.5 -> 1.5 falls a match in batch 1, and falls from marked areas 2.7 -> 0.4. For context, #2168's original timer version measured falls x0.90 [0.79, 1.00] in batch 1.

Narrow ledge: ntre_ridgeline_ctg's rail hop

The way onto ntre_ridgeline_ctg's pipe rack (NeotokyoRebuild/neoAssets#143) is a hop over a handrail: a 39 u climb onto the rail's 3 u top bar, then a 39 u drop to a crossbeam with 10 u of footing, both marked NAV_MESH_PRECISE. The ghost was pinned on the rack past the hop, with 12 bots of one class (or the even roster) per match, 3 matches for each spot and roster, at default weapon damage. #143's mesh was used with #2170 in the build in both arms, and arms were interleaved in one batch where noted.

without the airborne steering with it
hop traversals that end off the hop (on the post top or girder below) 45 of 191 (24 %) 17 of 165 (10 %)
of those, from the rail top 18 2
same batch, interleaved (48 matches) 23 of 94 9 of 94
traversals that reached the crossbeam and went on to the rack 78 of 113 (69 %) 66 of 90 (73 %)
traversals that ended back on the deck, from the rail top 58 71
matches in which the ghost was picked up 31 of 48 24 of 48

None of the falls is fatal, and only 8 of 62 had another player within 48 u when the bot went off. They are momentum from the climb, not shoves. With the steering, a bot that does not make it across falls back to the deck rather than off the far side. The pickup count is lower, but the per-traversal rates above give no mechanism for that, and at 48 matches it is within noise (one-sided p about 0.1). On a 36-match CTG survey of the same map with 30 bots and the ghost at its normal spawns, the change made no difference: bots seldom use the hop in normal play. Stuck events were 2.4 v 2.8 episodes a match and fell-off events 0.44 v 0.56 a match, within run-to-run noise.

Open problem: crowding on ledges

The extra stuck events sit on a handful of ledge areas (skyline, bullet, redlight). In batch 1, stuck events on marked areas with another player as the blocker went from 38 to 135. On the keys, a bot's heading wobbles and it slides past a teammate, sometimes off the ledge. On the exact direction, two bots on the same line push into each other and wait.

Two fixes were tried in batch 2 and did not help, so neither is in this PR:

fallback to the keys stuck on PRECISE / CLIFF falls
while another player is within 32 u ahead x1.59 [1.04, 2.45] x0.76
the same, and also while IsStuck() x1.62 [1.12, 2.42] x0.75

Next ideas: spread bots across the area's width instead of holding the path's center line, or give way on a marked area the way AvoidBumpingFriends does elsewhere, without the sideways step that #2168 turns off there.

Cost

On a marked area, one Vector2D store per bot update and a sine and cosine per tick. Nothing is traced.

Where it applies

No mesh on master marks PRECISE or CLIFF today, so on its own this changes nothing on the current maps. The meshes that need it are ntre_ridgeline_ctg's (NeotokyoRebuild/neoAssets#143), which marks its rail hop NAV_MESH_PRECISE and also needs #2170, and ntre_bullet_tdm's (NeotokyoRebuild/neoAssets#155), which marks the train cars' aisles.

Toolchain

  • Linux GCC Distro Native (Linux Mint 22.3, GCC 13.3.0)

Linked Issues

sunzenshen added a commit to sunzenshen/neo that referenced this pull request Oct 1, 2026
sunzenshen added a commit to sunzenshen/neo that referenced this pull request Oct 1, 2026
The settle block's merge left one brace too many in LadderClimb::Update,
and NeotokyoRebuild#2175's exact move direction on PRECISE / CLIFF areas replaces the
default-off patch 109 arm that declared the same local.
@sunzenshen
sunzenshen force-pushed the bot-nav-precise-move-direction branch from 96aeb64 to 0d8bcd3 Compare October 3, 2026 17:51
Bot movement presses the nearest of eight key combinations, up to 22.5
degrees off the goal, so a bot looking elsewhere drifts sideways - on a
ledge marked NAV_MESH_PRECISE or NAV_MESH_CLIFF, off the edge.

On those areas Approach() now hands the player the world direction to
the goal. PhysicsSimulate() applies it on every tick until the next bot
update, converted against that tick's view, so a bot turning to aim
keeps its line. The stock SetButtonScale() does not do this: its 0.01 s
timer lapses within a tick and it is relative to the view at update
time. Design by sunmachine (review of NeotokyoRebuild#2168).

Draft: measured falls down (x0.79, x0.69), but stuck events on these
areas up (x1.84, x1.42) as bots on a ledge push into each other.
In the air, move input only adds speed along the move direction (air
acceleration is capped per direction), so holding the direction to the
goal does not stop a bot's sideways momentum. A bot that climbs or
drops onto a narrow marked ledge carries its run-up speed past the
edge.

While airborne over a PRECISE or CLIFF area, the held move direction
is now the difference between the velocity toward the goal and the
current velocity, so air control cancels the sideways speed instead of
adding to it. On the ground nothing changes.

Measured on ntre_ridgeline_ctg's rail hop (a 3 u rail top and a
crossbeam with 10 u of footing, both PRECISE), ghost pinned past it, 12
bots per class roster, default damage: bots that went off the hop fell
from 24 % to 10 % of traversals (45 of 191 v 17 of 165), and falls
from the rail top from 18 to 2.
Comment-only: break the two lines at a clause boundary.
@sunzenshen
sunzenshen force-pushed the bot-nav-precise-move-direction branch from c00f5f5 to 0837917 Compare October 5, 2026 04:02
@sunzenshen sunzenshen changed the title Hold an exact move direction on PRECISE areas Bots hold an exact move direction on PRECISE areas Oct 5, 2026
@sunzenshen
sunzenshen requested a review from sunmachine October 5, 2026 06:06
@sunzenshen
sunzenshen marked this pull request as ready for review October 5, 2026 06:06
sunzenshen added a commit to sunzenshen/neo that referenced this pull request Oct 7, 2026
The settle block's merge left one brace too many in LadderClimb::Update,
and NeotokyoRebuild#2175's exact move direction on PRECISE / CLIFF areas replaces the
default-off patch 109 arm that declared the same local.
sunzenshen added a commit to sunzenshen/neo that referenced this pull request Oct 8, 2026
The settle block's merge left one brace too many in LadderClimb::Update,
and NeotokyoRebuild#2175's exact move direction on PRECISE / CLIFF areas replaces the
default-off patch 109 arm that declared the same local.
sunzenshen added a commit to sunzenshen/neo that referenced this pull request Oct 8, 2026
The settle block's merge left one brace too many in LadderClimb::Update,
and NeotokyoRebuild#2175's exact move direction on PRECISE / CLIFF areas replaces the
default-off patch 109 arm that declared the same local.
sunzenshen added a commit to sunzenshen/neo that referenced this pull request Oct 8, 2026
The settle block's merge left one brace too many in LadderClimb::Update,
and NeotokyoRebuild#2175's exact move direction on PRECISE / CLIFF areas replaces the
default-off patch 109 arm that declared the same local.

@sunmachine sunmachine left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It's straight-forward; no clear issues. Not even anything I could throw out.

@sunzenshen
sunzenshen merged commit 0707264 into NeotokyoRebuild:master Oct 9, 2026
10 checks passed
@sunzenshen sunzenshen added the Bots Related to bot players label Oct 9, 2026
sunzenshen added a commit to sunzenshen/neo that referenced this pull request Oct 13, 2026
The 3-way merge of the ladder files took the research tip's older
NeotokyoRebuild#2175 hunk in PlayerLocomotion::Approach over the merged version,
which also steers a PRECISE / CLIFF move in the air. Restore it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bots Related to bot players

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants