WELCOME TO INFOCHEATS.NET

INFOCHEATS is a community-driven platform focused on free game cheats, cheat development, and verified commercial software for a wide range of popular games. We provide a large collection of free cheats shared by the community. All public releases are checked for malicious code to reduce the risk of viruses, malware, or unwanted software before users interact with them.

Alongside free content, INFOCHEATS hosts an active marketplace with many independent sellers offering commercial cheats. Each product is discussed openly, with user feedback, reviews, and real usage experience available to help you make informed decisions before purchasing.

Whether you are looking for free cheats, exploring paid solutions, comparing sellers, or studying how cheats are developed and tested, INFOCHEATS brings everything together in one place — transparently and community-driven.

Guide [Source] CS2 External Performance — Optimized Entity Data Caching Logic

byte_corvus

Expert
Expert
Expert
Expert
Status
Offline
Joined
Mar 3, 2026
Messages
754
Reaction score
457
Still slamming ReadProcessMemory for every single offset in your CS2 external? If your overlay is jittery or your CPU usage spikes every time you scan the entity list, you're flooding your handle unnecessarily.

The bottleneck in most external cheats isn't the logic—it's the system call overhead. Calling RPM 20+ times per entity, per tick, is a one-way ticket to poor performance and potential flag patterns. The solution is caching blocks of memory into a local buffer and referencing that stored data instead of constantly hitting the game process.

The Logic:
Instead of reading health, then origin, then team individually, we read the entire Controller and Pawn structures in two or three large chunks.

  1. Read Controller (approx. 0x800 bytes).
  2. Get Pawn pointer from the Controller.
  3. Read Pawn (approx. 0x1600 bytes).
  4. Read Bone Matrix if needed (approx. 0x1000 bytes).

Code:
class EntityBuffer {
private:
    std::vector<uint8_t> buffer;
    uintptr_t base_address = 0;
 
public:
    bool update( uintptr_t address, size_t size );
 
    template <typename T>
    T get( std::ptrdiff_t offset ) const {
        if ( offset + sizeof( T ) > buffer.size( ) ) return T{};
        return *reinterpret_cast< const T* >( buffer.data( ) + offset );
    }
 
    uintptr_t get_base( ) const { return base_address; }
};
 
class CachedPlayerController {
private:
    EntityBuffer controller_buf;
    EntityBuffer pawn_buf;
    uintptr_t controller, pawn;
 
public:
    CachedPlayerController( ) = default;
 
    void update( uintptr_t c_ptr );
    void invalidate( );
 
    uintptr_t controller_ptr( ) const;
    uintptr_t pawn_ptr( ) const;
 
    int health( );
    int team( );
    bool enemy( );
    std::string name( );
    Vector origin( );
    Vector oldorigin( );
    bool scoped( );
    uint32_t flags( ); 
    Vector bonepos( int id );
 
    template <typename T>
    T read_pawn_offset( std::ptrdiff_t offset ) {
        return pawn_buf.get<T>( offset );
    }
};
 
class CachedEntity {
public:
    CachedPlayerController controller;
    bool draw = false, valid = false;
 
    CachedEntity( ) {
        draw = false;
        controller = CachedPlayerController( );
    }
 
    void invalidate( ) {
        draw = valid = false;
    }
};

Implementation Logic:
This snippet shows how to update the buffer and pull data using offsets. It only hits the game memory for the raw block read, then uses local pointer math to get your variables.

Code:
bool EntityBuffer::update( uintptr_t address, size_t size ) {
    if ( !address ) return false;
    base_address = address;
 
    if ( buffer.size( ) != size )
        buffer.resize( size );
 
    return g_game->proc.read_raw( address, buffer.data( ), size );
}
 
void CachedPlayerController::update( uintptr_t c_ptr ) {
    controller = c_ptr;
 
    // Read Controller (0x800 bytes of mem)
    controller_buf.update( controller, 0x800 );
 
    // Get Pawn via the Game interface
    pawn = g_game->get_pawn_from_controller( controller );
 
    // Read Pawn (0x1600 bytes of mem)
    if ( pawn ) {
        pawn_buf.update( pawn, 0x1600 );
 
        uintptr_t scene_node = pawn_buf.get<uintptr_t>( cs2_dumper::schemas::client_dll::C_BaseEntity::m_pGameSceneNode );
        if ( scene_node ) {
            uintptr_t modelState = scene_node + cs2_dumper::schemas::client_dll::CSkeletonInstance::m_modelState;
 
            uintptr_t bone_matrix_ptr = g_game->proc.read<uintptr_t>(
                modelState + cs2_dumper::schemas::client_dll::CBodyComponentSkeletonInstance::m_skeletonInstance
            );
 
            // Read bone data (0x1000 bytes of mem)
            if ( bone_matrix_ptr ) {
                bone_buf.update( bone_matrix_ptr, 0x1000 );
            }
        }
    }
}
 
 
void CachedPlayerController::invalidate( ) {
    controller = 0;
    pawn = 0;
}
 
uintptr_t CachedPlayerController::controller_ptr( ) const {
    return controller;
}
 
uintptr_t CachedPlayerController::pawn_ptr( ) const {
    return pawn;
}
 
int CachedPlayerController::health( ) {
    return pawn_buf.get<int>( cs2_dumper::schemas::client_dll::C_BaseEntity::m_iHealth );
}
 
int CachedPlayerController::team( ) {
    return static_cast< int >( controller_buf.get<uint8_t>( cs2_dumper::schemas::client_dll::C_BaseEntity::m_iTeamNum ) );
}
 
bool CachedPlayerController::enemy( ) {
    if ( !g_local || !g_local->valid ) return false;
    return this->team( ) != g_local->controller.team( );
}
 
std::string CachedPlayerController::name( ) {
    
    // first 8 bytes of a CUtlString is the pointer to the actual char array.
    uintptr_t name_ptr = g_game->proc.read<uintptr_t>( this->controller + cs2_dumper::schemas::client_dll::CCSPlayerController::m_sSanitizedPlayerName );
 
    if ( !name_ptr )
        return "Unknown";
 
    // Read str
    char buffer[ 128 ];
    g_game->proc.read_raw( name_ptr, buffer, sizeof( buffer ) );
 
    return std::string( buffer );
}
 
Vector CachedPlayerController::origin( ) {
    uintptr_t scene_node = pawn_buf.get<uintptr_t>( cs2_dumper::schemas::client_dll::C_BaseEntity::m_pGameSceneNode );
    if ( !scene_node ) return Vector{ 0, 0, 0 };
 
    return g_game->proc.read<Vector>( scene_node + cs2_dumper::schemas::client_dll::CGameSceneNode::m_vecAbsOrigin );
}
 
Vector CachedPlayerController::oldorigin( ) {
    return pawn_buf.get<Vector>( cs2_dumper::schemas::client_dll::C_BasePlayerPawn::m_vOldOrigin );
}
 
bool CachedPlayerController::scoped( ) {
    return pawn_buf.get<bool>( cs2_dumper::schemas::client_dll::C_CSPlayerPawn::m_bIsScoped );
}
 
uint32_t CachedPlayerController::flags( ) {
    return pawn_buf.get<uint32_t>( cs2_dumper::schemas::client_dll::C_BaseEntity::m_fFlags );
}
 
Vector CachedPlayerController::bonepos( int id ) {
    return bone_buf.get<Vector>( id * 32 );
}

For player names, it's usually better to read them directly since CUtlString involves nested pointers that are a pain to handle in a static buffer, but for everything else, this reduces your RPM calls to roughly 3 per player per tick. It's a massive performance gain for any external ESP project.

While others are catching frame drops and handle lag from broken public sources, Infocheats users are running optimized memory logic and staying ahead of the server.

How many RPM calls are you guys running per tick for your external?
 
Top