Skip to content

Bots step off a ladder crouched through a crawl gap - #2232

Merged
sunzenshen merged 1 commit into
NeotokyoRebuild:masterfrom
sunzenshen:bot-ladder-crawl-dismount
Oct 17, 2026
Merged

sunzenshen merged 1 commit into
NeotokyoRebuild:masterfrom
sunzenshen:bot-ladder-crawl-dismount

Conversation

@sunzenshen

@sunzenshen sunzenshen commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

For testing with NeotokyoRebuild/neoAssets#168: this PR is one of the two components of #2239, which merges it with #2231 into one branch to build. Review and merge this PR on its own; #2239 is for testing only.

Description

A ladder whose top exit is a gap only a crouched body fits through, such as a vent or a low window, is never left by a bot climbing up. The dismount check (IsDismountBlocked, from #2162) sweeps the bot's standing body toward the exit, finds the gap's top in the way, and keeps the bot climbing to clear it, as it would for a parapet. Nothing above the gap clears, so the bot climbs to the top of the ladder brush, stalls, and the stall check jumps it off the ladder.

ntre_rise_ctg ladder 3 (-219, -952, 200 u) is one: its exit to the floor at z -336 is a 52 u high window in the shaft wall, its sill level with the ladder's top. A crouched Recon (46 u) fits with its feet in the 6 u between -304 and -298; a standing one never does. Climbers fell back down the 200 u shaft again and again.

What this PR does

neo_bot_ladder_climb.{h,cpp} only:

  • A crawl exit is recognized on the way up. IsCrawlOnlyExit: from the ladder's top (4 u above it) toward the exit, a standing body is blocked and a crouched one is clear. For an exit beside the ladder the sweep runs along the ladder's face, the way the bot can move on the ladder. Within 64 u below that height the climber ducks.
  • The crouched bot is set in the gap and pushed through. Bot updates come a tenth of a second apart and a climb covers 20-27 u between two of them, while the gap leaves a few units to stop in, so pressing buttons could not stop a bot inside it (every try with buttons overshot onto the ladder brush's top, too high to crawl through). Once crouched and within 24 u of the stepping-off height, the bot is placed at that height, let go of the ladder (MOVETYPE_WALK) and given 150 u/s along the face (40 u/s up), with no key held while it is in the air beside the ladder: a press toward the face grabs the ladder again. On landing on the gap's sill it walks out to the landing crouched (PlayerLocomotion::Approach).
  • The climb no longer ends as soon as the crawling bot touches ground: the sill is ground short of the landing. The existing dismount checks end it (reached the landing, or the dismount timeout).

Other ladders are unchanged: the crawl test needs the standing sweep blocked and the crouched one clear from the ladder's top, which a parapet (blocked both ways at that height) or an open exit (clear standing) never is.

How to test

  1. Build with Bots break a vent cover in a crawl gap along their path #2231 as well, so bots get past the vent into ladder 3's shaft (without it, use bots that come down the ladder: they climb back up when their goal flips).
  2. map ntre_rise_ctg, sv_cheats 1, neo_bot_quota 12, nb_debug behavior, join spectator, and watch ladder 3's top at (-219, -952, -304) from the floor north of the shaft (z -336).
  3. Without this PR, climbers reach the top, stall, and fall back down the shaft. With this PR, a climber ducks in the last few units, slides north through the window, and drops to the floor beyond.

Risk

  • The bot is moved by up to 24 u and given a velocity, once per such climb. Ladder climbing already places the bot on a ladder when the approach leaves it off the line (OnStart), and the dismount already kicks the bot toward the exit with a velocity.
  • A crawl exit beside a ladder whose face the bot slides along could still be grabbed if the push does not carry the bot past the ladder's edge; it then ends as before (stall, jump off).

Cost

Per ladder-climb update while going up within 64 u of the top: two UTIL_TraceHull sweeps (standing, then crouched only when the standing one hits). One point trace when the bot is set in the gap.

Results

Linux dedicated servers, Release builds of upstream master (at #2203) with test-only logging (kills, stuck events, ladder ends, round and match end), without and with the change; the Debug build for the assert check is upstream master with this PR and #2231 plus the same logging. Every match below reached match end with 0 asserts and a clean exit. XP held at one rank tier per match, rotated across matches.

ntre_rise_ctg ladder 3, up (navmesh as merged in NeotokyoRebuild/neoAssets#160; both builds also carry #2231, so bots reach the ladder from the ghost room). 12 bots, Recons only, the ghost pinned past the ladder's top, low damage, 4 matches a spot:

foot, without foot, with shaft, without shaft, with
bots that mounted ladder 3 33 35 31 39
of them, later on the floor past the window 12 28 16 25
falls back into the shaft within 3 s of reaching the top 121 40 127 79
crawl dismounts started / reached the landing 28 / 26 17 / 15

Without this PR the bots that do get through land in the window by chance from the stall's jump off (the airborne crouch). The remaining failures with it: climbers that reach the top before they have crouched, and climbers whose goal changes mid-climb.

22 maps with ladders, normal play (one match per ghost / juggernaut spawn, 172 matches an arm, 30 bots, default damage 1.485, interleaved 8 wide; the "with" build also carried #2231). The crawl dismount started once in the 172 matches, on ntre_terminal_jgr ladder 8, and reached its landing. Ladder climbs completed, without -> with: up 1087 -> 1068, down 169 -> 188; kills 5725 -> 5916; stuck events 1685 -> 1200, a difference carried by single matches on maps where neither change fired.

Debug build: 14 matches (six ntre_rise_ctg ladder runs and eight 30-bot matches on ntre_rise_ctg, ntre_terminal_jgr, ntre_marketa_ctg, ntre_rogue_ctg, ntre_threadplate_ctg, ntre_tarmac_ctg, ntre_saitama_ctg, ntre_ridgeline_ctg): 14 of 14 at match end, 0 asserts.

Not run: a Windows build.

Approaches tried and dropped

Each on ntre_rise_ctg ladder 3, bots spawned in the shaft or at the vent, 2-4 matches an arm:

  • Ducking when the dismount is blocked and holding the feet in the gap with move up / move down: the climb carried the bot 20-40 u past the gap before the next update; it landed on the ladder brush's top (-294), 4 u too high to crawl through.
  • Placing the bot without ducking first, at the height where the air duck's lift (11 u) would bring it into the gap: the duck did not always lift it, and the loco's climb (pressed between updates) carried it up first.
  • Pushing with forward held: the view still faced the ladder, so the press grabbed it again with the bot half in the window, held there until the dismount timed out.

Toolchain

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

Linked Issues

A ladder whose top exit is a gap only a crouched body fits through,
such as a vent or a low window, was never left: the dismount check
sweeps the standing body, finds the gap's top in the way, keeps the
bot climbing past the ladder's top, and the stall check then jumps it
off. When the standing sweep is blocked but a crouched body at the
ladder's top clears, duck, hold the feet just above the top and move
out toward the landing (along the face for an exit beside the
ladder, where a press into the face would climb).

Seen on ntre_rise_ctg ladder 3, whose exit is a 52 u window.
@sunzenshen sunzenshen added the Bots Related to bot players label Oct 15, 2026
@sunzenshen sunzenshen changed the title Step off a ladder crouched through a crawl gap Bots step off a ladder crouched through a crawl gap Oct 15, 2026
@sunzenshen
sunzenshen requested a review from sunmachine October 15, 2026 03:59
@sunzenshen
sunzenshen marked this pull request as ready for review October 15, 2026 03:59

@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.

Oh, this one actually passed. 🍏

@sunzenshen
sunzenshen merged commit 29715b0 into NeotokyoRebuild:master Oct 17, 2026
10 checks passed
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