Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/game/server/neo/bot/neo_bot_locomotion.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,21 @@ class CNEOBotLocomotion : public PlayerLocomotion

inline float CNEOBotLocomotion::GetMaxJumpHeight( void ) const
{
// NEO JANK: Assumes [MD]'s g_bMovementOptimizations = true, where we assume sv_gravity is 800 for navigation.
// Changing that setting can potentially break bot navigation.
Comment on lines +41 to +42
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would be good to debug-assert sv_gravity == 800 here if we're hardcoding that assumption, so that this blows up more prominently when that is not the case.

auto me = (CNEO_Player*)GetBot()->GetEntity();
switch (me->GetClass())
{
case NEO_CLASS_RECON:
return NEO_RECON_CROUCH_JUMP_HEIGHT;
case NEO_CLASS_ASSAULT:
[[fallthrough]];
case NEO_CLASS_JUGGERNAUT:
return NEO_JUGGERNAUT_CROUCH_JUMP_HEIGHT;
case NEO_CLASS_SUPPORT:
[[fallthrough]];
return NEO_SUPPORT_CROUCH_JUMP_HEIGHT;
case NEO_CLASS_VIP:
[[fallthrough]];
case NEO_CLASS_JUGGERNAUT:
return NEO_CROUCH_JUMP_HEIGHT;
return NEO_ASSAULT_CROUCH_JUMP_HEIGHT; // vip same as assault
case NEO_CLASS_ASSAULT:
return NEO_ASSAULT_CROUCH_JUMP_HEIGHT;
default:
Assert(false);
return 0.f;
Expand Down
1 change: 1 addition & 0 deletions src/game/shared/gamemovement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2575,6 +2575,7 @@ bool CGameMovement::CheckJumpButton( void )
flMul = sqrt(2 * GetCurrentGravity() * GAMEMOVEMENT_JUMP_HEIGHT);
}
#else
// NEO JANK: Remember to update NEO_RECON_CROUCH_JUMP_HEIGHT/etc if you change these values.
auto neoPlayer = static_cast<CNEO_Player*>(player);
if ( g_bMovementOptimizations )
{
Expand Down
50 changes: 49 additions & 1 deletion src/game/shared/neo/neo_player_shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,56 @@ COMPILE_TIME_ASSERT(NEO_RECON_CROUCH_SPEED > NEO_ASSAULT_CROUCH_SPEED);
COMPILE_TIME_ASSERT(NEO_ASSAULT_CROUCH_SPEED == NEO_SUPPORT_CROUCH_SPEED);
COMPILE_TIME_ASSERT(NEO_ASSAULT_CROUCH_SPEED == NEO_VIP_CROUCH_SPEED);

// NEO Jank: As an optimization, these constants are calculated for default gravity,
// and bot climbing behavior may be odd if sv_gravity is changed.
// See [MD]'s g_bMovementOptimizations for additional context.
//
// At time of comment, these constants were only used by neo_bot_locomotion.h
// where these values determine if a bot will attempt to climb a ledge between NavAreas.
// At time of analysis, NEO_RECON_CROUCH_JUMP_HEIGHT potentially was historically calculated based on
// (GAMEMOVEMENT_JUMP_HEIGHT * class multiplier) + (Support Hull Crouch/Stand Difference),
//
// From this point on we will refer to (GAMEMOVEMENT_JUMP_HEIGHT * class multiplier) as "Class Jump Height".
// For sake of consistency, we will use the precomputed jump heights assuming g_bMovementOptimizations = true.
//
// Class Jump Height: Derived from `sqrt(2 * gravity * jump_height)` from `gamemovement.cpp`.
// But for simplicity we use the optimized values provided under the g_bMovementOptimizations = true case:
// - Recon: 54.0 units
// - Juggernaut: 50.4 units
// - Others: 36.0 units
//
// Hull Crouch/Stand Difference (aka: "Lift"):
// ---
// Derived from neo_gamerules.cpp: Vector viewDelta = ( hullSizeNormal - hullSizeCrouch );
// Variables are defined in shareddefs.h as VEC_HULL_MAX_SCALED and VEC_DUCK_HULL_MAX_SCALED.
// Instead of deriving these values by hand, a breakpoint can be placed in CGameMovement::CanUnduck()
// while configuring the bot class with the bot_class command, to log the variable values.
//
// Lift = VEC_HULL_MAX_SCALED.z - VEC_DUCK_HULL_MAX_SCALED.z
// ---
// Recon: 64 - 46 = 18
// Assault: 65 - 48 = 17
// Support: 70 - 59 = 11
// VIP: 65 - 48 = 17
//
// Juggernaut: 88 - 75 = 13
// (Base Hull Max = 70) + (NEO_JUGGERNAUT_MAXHULL_OFFSET.z = 18) = 88
// (Base Hull Duck Max = 59) + (NEO_JUGGERNAUT_DUCK_MAXHULL_OFFSET.z = 16) = 75
//
// Then apply a uniform spare height budget gap of 7 units to all classes.
// Formula: (Class Jump Height) + (Lift) - (Spare Gap)
//
// Precalculated bot crouch jump heights for use in bot locomotion/navigation checks:
// ---
// Recon: 54 + 18 - 7 = 65
// Assault/VIP: 36 + 17 - 7 = 46
// Support: 36 + 11 - 7 = 40
// Juggernaut: 50.4 + 13 - 7 = 56.4 (rounded down to 56)

#define NEO_RECON_CROUCH_JUMP_HEIGHT 65.f
#define NEO_CROUCH_JUMP_HEIGHT 56.f
#define NEO_ASSAULT_CROUCH_JUMP_HEIGHT 46.f
#define NEO_SUPPORT_CROUCH_JUMP_HEIGHT 40.f
#define NEO_JUGGERNAUT_CROUCH_JUMP_HEIGHT 56.f
Comment on lines 169 to +172
Copy link
Collaborator

@Rainyan Rainyan Jan 20, 2026

Choose a reason for hiding this comment

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

Are these values intended to reflect the actual maximum crouch-jump heights for the classes? The recon (65 units) and assault (46 units) values are accurate, however the support value seems incorrect. Supports have the same max jump height as the assault, AFAIK.

You can test this in the devbox map with sv_neo_can_change_classes_anytime 1, using the ledges that go up in 1 unit increments (there's a visual marker per every 16 units).

As for the JGR, I have no idea, couldn't figure out how to spawn as one. I guess I can try to recompile the devbox in JGR mode later...

Also should be noted, the 65 and 46 values are for the crouch-first-then-jump (or possibly crouch & jump on same exact tick? i'm unsure) maximums; for a more typical user input (jump-then-crouch), the max heights are about 1 unit less. But I guess the bots should know how to use the optimum one, because some jumps in some maps do indeed use the crouch-first value as a form of a "trick jump", or just by coincidence, and we probably do want the bots to be able to perform these jumps that normal players also could.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh, I see you've touched upon this in #1558 (comment) already.

Copy link
Collaborator

@Rainyan Rainyan Jan 20, 2026

Choose a reason for hiding this comment

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

Personally not a huge fan of fuzzing the variables with some magic offset, especially with a descriptive name like <CLASSNAME>_CROUCH_JUMP_HEIGHT - would prefer we separated any such magic as its own value separate from what we know is the real max height clearance. But for the sake of getting these nav improvements in the game, I guess we can merge this and leave the refactoring for another time.

One way we could decouple the real jump heights could perhaps be to return <CLASSNAME>_CROUCH_JUMP_HEIGHT + /* some offset as required */ from CNEOBotLocomotion::GetMaxJumpHeight, so it was more obvious what's going on when looking at the code, rather than directly modifying the defines to differ from the empirical values.


// END OF NEO MOVEMENT DEFINITIONS
//////////////////////////////////////////////////////
Expand Down