The HotWheels SDK movement system provides automated and assisted movement features for CS:GO, including bunny hopping, jump bugs, and edge detection.
Overview
The movement module (hacks/features/movement/) implements:
- Bunny hop (auto jump)
- Edge jump detection
- Jump bug exploit
- Mini jump
- Auto-align for pixel-perfect movement
- Movement vector correction
Architecture
The movement system operates in two phases:
struct impl {
struct pre_prediction {
void think( );
} pre_prediction;
struct post_prediction {
void think( );
} post_prediction;
};
Source: hacks/features/movement/movement.h:17-23
Pre-prediction handles features that modify input before game physics, while post-prediction handles features that require physics results.
Bunny Hop
Automatic bunny hopping removes jump input when the player is airborne:
void movement::impl::bhop( )
{
// its a bhop hack
[[unlikely]] if ( !g_config.find< bool >( HASH( "m_bh" ) ) ) return;
if ( g_config.find< bool >( HASH( "m_jb" ) ) &&
g_input.key_state( input::key_state_t::KEY_DOWN, g_config.find< int >( HASH( "m_jb_key" ) ) ) )
return;
// will return if player is noclip/ladder/fly mode
[[unlikely]] if ( g_ctx.local->move_type( ).has_any_of(
{ sdk::move_type::MOVE_NOCLIP, sdk::move_type::MOVE_LADDER, sdk::move_type::MOVE_FLY } ) ) return;
// remove jump flag if player in air
if ( !g_ctx.local->flags( ).has( sdk::flags::ONGROUND ) )
g_ctx.cmd->buttons.remove( sdk::buttons::IN_JUMP );
}
Source: hacks/features/movement/movement.cpp:131-146
Bunny hop is disabled when jump bug is active to prevent conflicts.
Edge Jump
Detects when the player leaves the ground and automatically jumps:
Detect Edge
Check if player was on ground last tick but is airborne now
Auto Jump
Add the jump button to maintain velocity
Long Jump (Optional)
Duck for 2 ticks after edge jump for extended distance
Implementation
void movement::impl::edge_jump( )
{
if ( !g_config.find< bool >( HASH( "m_ej" ) ) ||
!g_input.key_state( input::key_state_t::KEY_DOWN, g_config.find< int >( HASH( "m_ej_key" ) ) ) ) {
g_movement.longjump.start_timer = false;
g_movement.longjump.time_stamp = 0;
return;
}
if ( g_prediction.backup_vars.flags.has( sdk::flags::ONGROUND ) &&
!g_ctx.local->flags( ).has( sdk::flags::ONGROUND ) ) {
g_ctx.cmd->buttons.add( sdk::buttons::IN_JUMP );
g_movement.longjump.start_timer = true;
g_movement.longjump.time_stamp = g_interfaces.globals->tick_count;
}
// Long jump extension
[[likely]] if ( g_config.find< bool >( HASH( "m_lj" ) ) ) {
if ( g_movement.longjump.start_timer ) {
if ( g_movement.longjump.time_stamp + 2 > g_interfaces.globals->tick_count ) {
g_ctx.cmd->buttons.add( sdk::buttons::IN_DUCK );
g_ctx.cmd->forward_move = 0;
} else {
g_movement.longjump.start_timer = false;
}
}
}
}
Source: hacks/features/movement/movement.cpp:36-71
Jump Bug
Exploits CS:GO physics to negate fall damage:
void movement::impl::jump_bug( )
{
if ( !g_config.find< bool >( HASH( "m_jb" ) ) )
return;
if ( !g_input.key_state( input::key_state_t::KEY_DOWN, g_config.find< int >( HASH( "m_jb_key" ) ) ) )
return;
[[unlikely]] if ( g_ctx.local->move_type( ).has_any_of(
{ sdk::move_type::MOVE_NOCLIP, sdk::move_type::MOVE_LADDER, sdk::move_type::MOVE_FLY } ) ) return;
if ( g_ctx.local->flags( ).has( sdk::flags::ONGROUND ) ) {
if ( !g_prediction.backup_vars.flags.has( sdk::flags::ONGROUND ) )
g_ctx.cmd->buttons.add( sdk::buttons::IN_DUCK );
g_ctx.cmd->buttons.remove( sdk::buttons::IN_JUMP );
}
// secret sauce
if ( !g_ctx.local->flags( ).has( sdk::flags::ONGROUND ) &&
g_prediction.backup_vars.flags.has( sdk::flags::ONGROUND ) )
g_ctx.cmd->buttons.remove( sdk::buttons::IN_DUCK );
}
Source: hacks/features/movement/movement.cpp:73-113
Jump bug activates by ducking on the exact tick the player lands, canceling fall damage.
Mini Jump
Combines jump and duck for lower jump height:
void movement::impl::mini_jump( )
{
if ( !g_config.find< bool >( HASH( "m_mj" ) ) )
return;
if ( !g_input.key_state( input::key_state_t::KEY_DOWN, g_config.find< int >( HASH( "m_mj_key" ) ) ) )
return;
[[unlikely]] if ( g_ctx.local->move_type( ).has_any_of(
{ sdk::move_type::MOVE_NOCLIP, sdk::move_type::MOVE_LADDER, sdk::move_type::MOVE_FLY } ) ) return;
if ( g_prediction.backup_vars.flags.has( sdk::flags::ONGROUND ) &&
!g_ctx.local->flags( ).has( sdk::flags::ONGROUND ) ) {
g_ctx.cmd->buttons.add( sdk::buttons::IN_DUCK | sdk::buttons::IN_JUMP );
}
}
Source: hacks/features/movement/movement.cpp:115-129
Auto-Align
Automatically aligns player position to unit grid for pixel-perfect movement:
Check Alignment Need
Determine if player position is within alignment threshold (0.03125 units)
Detect Wall Collision
Ray trace in 4 directions to find nearby walls
Calculate Strafe Angle
Compute optimal movement angle based on velocity and wall direction
Apply Movement Correction
Rotate movement input to align with calculated angle
Implementation
void movement::impl::auto_align( )
{
if ( !g_config.find< bool >( HASH( "m_auto_align" ) ) )
return;
[[unlikely]] if ( g_ctx.local->move_type( ).has_any_of(
{ sdk::move_type::MOVE_NOCLIP, sdk::move_type::MOVE_LADDER, sdk::move_type::MOVE_FLY } ) ) return;
if ( g_prediction.backup_vars.flags.has( sdk::flags::ONGROUND ) ||
g_prediction.backup_vars.velocity.length_2d( ) < 10.f )
return;
const math::vec3 origin = g_ctx.local->get_abs_origin( );
const math::vec3 velocity = g_ctx.local->velocity( );
// Check if alignment is needed
const auto has_to_align = []( ) -> bool {
const auto origin = g_ctx.local->get_abs_origin( );
const math::vec2 remainder1 = math::vec2( 1.f - ( origin.x - floor( origin.x ) ),
1.f - ( origin.y - floor( origin.y ) ) );
const math::vec2 remainder2 = math::vec2( ( origin.x - floor( origin.x ) ),
( origin.y - floor( origin.y ) ) );
return ( ( remainder1.x >= movement::distance_to_stop && remainder1.x <= movement::distance_till_adjust ) ||
( remainder1.y >= movement::distance_to_stop && remainder1.y <= movement::distance_till_adjust ) ) ||
( ( remainder2.x >= movement::distance_to_stop && remainder2.x <= movement::distance_till_adjust ) ||
( remainder2.y >= movement::distance_to_stop && remainder2.y <= movement::distance_till_adjust ) );
};
if ( !has_to_align( ) )
return;
// Calculate strafe angle
float angle_diff = math::rad2deg( atan( ( g_ctx.cmd->buttons.has( sdk::buttons::IN_DUCK ) ? 4.6775f : 4.5500f ) /
velocity.length_2d( ) ) ) * ( 2.f * math::util::pi_f );
math::vec3 angle = { g_ctx.cmd->view_angles.x,
math::normalize_yaw( base_yaw + direction * angle_diff ),
g_ctx.cmd->view_angles.z };
g_movement.rotate_movement( angle );
}
Source: hacks/features/movement/movement.cpp:166-240
Alignment Constants
constexpr float distance_to_stop = 0.00100f;
constexpr float distance_till_adjust = 0.03125f;
Source: hacks/features/movement/movement.h:8-9
Auto-align only works while airborne with velocity > 10 units/sec. Ground movement is not affected.
Movement Correction
Corrects movement vectors after angle changes:
void movement::impl::rotate_movement( math::vec3& angle )
{
if ( angle.is_zero( ) )
angle = g_interfaces.engine->get_view_angles( );
math::vec3 vec_move( g_ctx.cmd->forward_move, g_ctx.cmd->side_move, g_ctx.cmd->up_move );
math::vec3 ang_move{ };
math::vector_angles( vec_move, ang_move );
const float speed = vec_move.length_2d( );
const float rotation = math::deg2rad( g_ctx.cmd->view_angles.y - angle.y + ang_move.y );
g_ctx.cmd->forward_move = std::cosf( rotation ) * speed;
g_ctx.cmd->side_move = std::sinf( rotation ) * speed;
}
Source: hacks/features/movement/movement.cpp:148-164
Execution Pipeline
void movement::impl::pre_prediction::think( )
{
if ( !g_ctx.local->is_alive( ) || !g_interfaces.engine->is_fully_connected( ) )
return;
if ( !g_ctx.cmd->buttons.has( sdk::IN_BULLRUSH ) && g_config.find< bool >( HASH( "m_fast_duck" ) ) )
g_ctx.cmd->buttons.add( sdk::IN_BULLRUSH );
g_movement.bhop( );
}
Source: hacks/features/movement/movement.cpp:6-29
API Reference
bhop()
Automatic bunny hop implementation.
edge_jump()
Detects and executes edge jumps with optional long jump.
jump_bug()
Performs jump bug to negate fall damage.
mini_jump()
Executes lower-height jumps.
auto_align()
Aligns player to unit grid for pixel-perfect movement.
rotate_movement(angle)
Corrects movement vectors after view angle changes.
Parameters:
angle - Target view angle for movement correction