Skip to main content
The console utility provides a colored logging system for debugging and runtime information display.

Initialization

init

Initialize the console window.
bool console::init()
if (!console::init()) {
    MessageBox(nullptr, "Failed to initialize console", "Error", MB_OK);
    return false;
}
return
bool
Returns true if console was successfully created, false otherwise
Call this once during DLL initialization to create a console window for your cheat.

unload

Clean up and free the console.
void console::unload()
console::unload();
FreeLibrary(hModule);

Logging

print

Print formatted messages to the console with color-coded log levels.
template<console::log_level lev, typename... VA>
void print(std::string_view print, VA&&... args)
console::print<console::log_level::NORMAL>("SDK initialized");
console::print<console::log_level::NORMAL>("Player count: {}", playerCount);

Log Levels

log_level Enum

NORMAL
log_level
Standard information messages (default white color)
DEBUG
log_level
Debug information for development (cyan color)
SUCCESS
log_level
Success/confirmation messages (green color)
WARNING
log_level
Warning messages for non-critical issues (yellow color)
FATAL
log_level
Fatal errors and critical failures (red color)

Console Colors

The logging system uses Windows console colors defined in log_colors enum:
enum log_colors : int {
    BLACK = 0,
    DARK_BLUE = 1,
    DARK_GREEN,
    DARK_CYAN,
    DARK_RED,
    DARK_PURPLE,
    DARK_YELLOW,
    DARK_WHITE,
    GRAY,
    BLUE,
    GREEN,
    CYAN,
    RED,
    PURPLE,
    YELLOW,
    WHITE
};

set_console_color

Manually set console text color.
void set_console_color(const console::log_level level)
This function is called automatically by print(). You rarely need to use it directly.

String Formatting

format

Format a string with arguments (used internally by print).
template<typename... VA>
std::string format(std::string_view fmt, VA&&... args)
std::string message = console::format("Player {} at position ({}, {}, {})", 
                                     playerName, x, y, z);

Common Patterns

Initialization Logging

DWORD WINAPI MainThread(LPVOID param) {
    if (!console::init()) {
        return 1;
    }
    
    console::print<console::log_level::NORMAL>("=== HotWheels SDK ===");
    console::print<console::log_level::NORMAL>("Version: 1.0.0");
    console::print<console::log_level::NORMAL>("Initializing...");
    
    if (!g_interfaces.init()) {
        console::print<console::log_level::FATAL>("Failed to initialize interfaces");
        console::unload();
        return 1;
    }
    
    console::print<console::log_level::SUCCESS>("Interfaces initialized");
    
    // More initialization...
    
    console::print<console::log_level::SUCCESS>("SDK loaded successfully");
    return 0;
}

Debug Logging

void update_entity_list() {
    console::print<console::log_level::DEBUG>("Updating entity list...");
    
    int validPlayers = 0;
    for (int i = 0; i < 65; i++) {
        auto player = g_interfaces.entity_list->get_client_entity<sdk::c_cs_player*>(i);
        if (!player || !player->is_alive())
            continue;
            
        validPlayers++;
        console::print<console::log_level::DEBUG>("Player {}: {} (HP: {})", 
                                                 i, player->name(), player->health());
    }
    
    console::print<console::log_level::DEBUG>("Found {} valid players", validPlayers);
}

Error Handling

bool load_config(const std::string& filename) {
    console::print<console::log_level::NORMAL>("Loading config: {}", filename);
    
    std::ifstream file(filename);
    if (!file.is_open()) {
        console::print<console::log_level::WARNING>("Config file not found: {}", filename);
        console::print<console::log_level::WARNING>("Creating default config...");
        create_default_config(filename);
        return false;
    }
    
    try {
        // Parse config...
        console::print<console::log_level::SUCCESS>("Config loaded: {}", filename);
        return true;
    }
    catch (const std::exception& e) {
        console::print<console::log_level::FATAL>("Failed to parse config: {}", e.what());
        return false;
    }
}

Conditional Debug Logging

#ifdef _DEBUG
    #define DEBUG_LOG(msg, ...) console::print<console::log_level::DEBUG>(msg, __VA_ARGS__)
#else
    #define DEBUG_LOG(msg, ...)
#endif

void process_player(sdk::c_cs_player* player) {
    DEBUG_LOG("Processing player: {}", player->name());
    
    auto origin = player->get_abs_origin();
    DEBUG_LOG("Position: ({:.2f}, {:.2f}, {:.2f})", origin.x, origin.y, origin.z);
    
    // Process player...
}

Hook Status Logging

class EndSceneHook {
public:
    static bool install() {
        console::print<console::log_level::NORMAL>("Installing EndScene hook...");
        
        auto device = get_d3d9_device();
        if (!device) {
            console::print<console::log_level::FATAL>("Failed to get D3D9 device");
            return false;
        }
        
        original = hook_vtable(device, 42, &hooked);
        if (!original) {
            console::print<console::log_level::FATAL>("Failed to hook EndScene");
            return false;
        }
        
        console::print<console::log_level::SUCCESS>("EndScene hooked at {:#x}", 
                                                    (uintptr_t)original);
        return true;
    }
};

Performance Profiling

void profile_function() {
    auto start = std::chrono::high_resolution_clock::now();
    
    // Execute code...
    
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    
    console::print<console::log_level::DEBUG>("Function took {} μs", duration.count());
}

Best Practices

Use appropriate log levels:
  • NORMAL for general information and user-facing messages
  • DEBUG for detailed diagnostic information during development
  • SUCCESS for confirmation of successful operations
  • WARNING for recoverable issues that need attention
  • FATAL for critical errors that prevent normal operation
Always unload the console before unloading your DLL to prevent crashes.
The console uses C++20 formatting. Format specifiers like {}, {:.2f}, {:#x} are supported.

Build docs developers (and LLMs) love