SDK Documentation
CLEO 5 SDK allows developers to create new opcodes for GTA San Andreas.
Version Information
Current Version: 5.3.0
The SDK uses a versioning system with main, major, and minor components:
#define CLEO_VERSION_MAIN 5
#define CLEO_VERSION_MAJOR 3
#define CLEO_VERSION_MINOR 0
The combined version is calculated as: 0x05030000
Enumerations
Version Enums
eCLEO_Version - Represents different CLEO versions for compatibility checking.
| CLEO_VER_3 | CLEO version 3.x (0x03000000) |
| CLEO_VER_4_MIN | Minimum CLEO 4 version (0x04000000) |
| CLEO_VER_4_2 | CLEO version 4.2 (0x04020000) |
| CLEO_VER_4_3 | CLEO version 4.3 (0x04030000) |
| CLEO_VER_4_4 | CLEO version 4.4 (0x04040000) |
| CLEO_VER_4 | Alias for CLEO_VER_4_4 |
| CLEO_VER_5 | CLEO version 5.x (0x05000000) |
| CLEO_VER_CUR | Current CLEO version |
eGameVersion - Identifies the game version.
| GV_US10 | 1.0 US version |
| GV_US11 | 1.01 US version (not supported) |
| GV_EU10 | 1.0 EU version |
| GV_EU11 | 1.01 EU version |
| GV_STEAM | Steam version |
| GV_TOTAL | Total number of versions |
| GV_UNK | Unknown version (-1) |
Callbacks
eCallbackId - Callback types for event handling.
| GameBegin (0) void WINAPI OnGameBegin(DWORD saveSlot) |
Game session started (-1 if new game) |
| GameProcessBefore (1) void WINAPI OnGameProcessBefore() |
Before frame processing |
| GameProcessAfter (14) void WINAPI OnGameProcessAfter() |
After frame processing |
| GameEnd (2) void WINAPI OnGameEnd() |
Game session ended |
| ScriptsLoaded (3) void WINAPI OnScriptsLoaded() |
All scripts loaded |
| ScriptsFinalize (4) void WINAPI OnScriptsFinalize() |
Scripts deleted |
| ScriptRegister (5) void WINAPI OnScriptRegister(CRunningScript*) |
Script created |
| ScriptUnregister (6) void WINAPI OnScriptUnregister(CRunningScript*) |
Before script deletion |
|
ScriptProcessBefore (7) bool WINAPI OnScriptProcessBefore(CRunningScript*) |
Before script processing |
|
ScriptProcessAfter (15) void WINAPI OnScriptProcessAfter(CRunningScript*) |
After script processing |
|
ScriptOpcodeProcessBefore (8) OpcodeResult WINAPI OnScriptOpcodeProcessBefore(CRunningScript*, DWORD) |
Before opcode execution |
|
ScriptOpcodeProcessAfter (9) OpcodeResult WINAPI OnScriptOpcodeProcessAfter(CRunningScript*, DWORD, OpcodeResult) |
After opcode execution |
| ScriptDraw (10) void WINAPI OnScriptDraw(bool beforeFade) |
Script drawing |
| DrawingFinished (11) void WINAPI OnDrawingFinished() |
After rendering, before screen presentation |
| Log (12) void OnLog(eLogLevel level, const char* msg) |
Log message event |
| MainWindowFocus (13) void WINAPI OnMainWindowFocus(bool active) |
Window focus changed |
Other Enums
eLogLevel - Log severity levels.
| None | No logging |
| Error | Errors and warnings |
| Debug | Debug mode/user traces |
| Default | All log messages |
OpcodeResult - Opcode execution results.
| OR_NONE (-2) | No result |
| OR_ERROR (-1) | Error occurred |
| OR_CONTINUE (0) | Continue execution |
| OR_INTERRUPT (1) | Interrupt execution |
eLogicalOperation - Logical operations for conditional expressions.
| NONE (0) | No operation |
| ANDS_1–ANDS_8 (1-8) | Number of AND operators |
| ORS_1–ORS_8 (21-28) | Number of OR operators |
Constants
String Length
MAX_STR_LEN: Maximum string parameter length (255 characters)
Virtual Path Prefixes
root:
|
Game root directory |
user:
|
Game save directory |
.
|
Current script directory |
cleo:
|
game\cleo directory |
modules:
|
game\cleo\cleo_modules directory |
Data Structures
SCRIPT_VAR Union
A union for storing different parameter types:
union SCRIPT_VAR {
DWORD dwParam; // 32-bit unsigned integer
short wParam; // 16-bit signed integer
WORD usParam; // 16-bit unsigned integer
BYTE ucParam; // 8-bit unsigned integer
char cParam; // 8-bit signed char
bool bParam; // Boolean
int nParam; // 32-bit signed integer
float fParam; // 32-bit float
void* pParam; // Generic pointer
char* pcParam; // String pointer
};
StringList Structure
Container for string arrays:
struct StringList {
DWORD count; // Number of strings
char** strings; // Array of string pointers
};
CRunningScript Class
The main class representing a running script instance.
Class Members
| Member | Type | Offset | Description |
| -------------------| ------------------| ------ | ------------------------------ |
| Next | CRunningScript* | 0x00 | Next script in queue |
| Previous | CRunningScript* | 0x04 | Previous script in queue |
| Name | char[8] | 0x08 | Script name (from 03A4 opcode) |
| BaseIP | void* | 0x10 | Script base pointer |
| CurrentIP | BYTE* | 0x14 | Current instruction pointer |
| Stack | BYTE*[8] | 0x18 | Return stack |
| SP | WORD | 0x38 | Stack pointer |
| LocalVar | SCRIPT_VAR[32] | 0x3C | Local variables |
| Timers | DWORD[2] | 0xBC | Script timers |
| bIsActive | bool | 0xC4 | Active status |
| bCondResult | bool | 0xC5 | Condition result |
| bUseMissionCleanup | bool | 0xC6 | Mission cleanup flag |
| bIsExternal | bool | 0xC7 | External script flag |
| bTextBlockOverride | bool | 0xC8 | Text block override |
| bExternalType | BYTE | 0xC9 | External type |
| WakeTime | DWORD | 0xCC | Wake time after wait |
| LogicalOp | eLogicalOperation | 0xD0 | Logical operation |
| NotFlag | bool | 0xD2 | NOT flag |
| bWastedBustedCheck | bool | 0xD3 | Wasted/busted check |
| bWastedOrBusted | bool | 0xD4 | Player wasted/busted |
| SceneSkipIP | void* | 0xD8 | Scene skip label |
| bIsMission | bool | 0xDC | Mission script flag |
| ScmFunction | WORD | 0xDD | SCM function ID |
| bIsCustom | bool | 0xDF | CLEO script flag |
Key Methods
Status Methods
| bool IsActive() | Check if script is active |
| bool IsExternal() | Check if script is external |
| bool IsMission() | Check if script is a mission |
| bool IsCustom() | Check if script is a CLEO script |
Variable Access
| SCRIPT_VAR* GetVarPtr() | Get pointer to local variables |
| int GetIntVar(int i) | Get integer variable value |
| void SetIntVar(int i, int v) | Set integer variable value |
| void SetFloatVar(int i, float v) | Set float variable value |
Script Control
| void Jump(int offset) | Jump to label |
| OpcodeResult Suspend() | Suspend script execution forever |
| void SetConditionResult(bool result) | Set condition result |
Data Reading
| BYTE ReadByte() | Read byte and advance pointer |
| WORD ReadWord() | Read word and advance pointer |
| DWORD ReadDword() | Read dword and advance pointer |
| eDataType PeekDataType() | Peek next data type without advancing |
Type Checking Functions
| IsImmInteger(eDataType) | Check if type is immediate integer (byte/word/dword) |
| IsImmFloat(eDataType) | Check if type is immediate float |
| IsImmString(eDataType) | Check if type is immediate string |
| IsVarString(eDataType) | Check if type is string variable |
| IsVariable(eDataType) | Check if type can carry int/float/pointer |
| IsArray(eDataType) | Check if type is an array |
Type Conversion Functions
| ToStr(eDataType) | Convert data type to string representation |
| ToKindStr(eDataType, eArrayDataType) | Get simplified type kind string |
SDK Functions
Version and System Information
| DWORD WINAPI CLEO_GetVersion() | Returns the CLEO version number |
| LPCSTR WINAPI CLEO_GetVersionStr() | Returns version string (e.g., "5.0.0-alpha.1") |
| eGameVersion WINAPI CLEO_GetGameVersion() | Returns the detected game version |
Opcode Functions
| BOOL WINAPI CLEO_RegisterOpcode(WORD opcode, CustomOpcodeHandler callback) | Register a custom opcode handler |
| BOOL WINAPI CLEO_RegisterCommand(const char* commandName, CustomOpcodeHandler callback) | Register a command by name (uses sa.json for opcode mapping) |
| OpcodeResult WINAPI CLEO_CallNativeOpcode(CRunningScript* script, WORD opcode) | Call native opcode handler; script IP must point to parameter data |
Script Management
Script Information
| BOOL WINAPI CLEO_IsScriptRunning(const CRunningScript* thread) | Check if a script is currently running |
| LPCSTR WINAPI CLEO_GetScriptFilename(const CRunningScript* thread) | Get script filename (returns nullptr if invalid) |
| void WINAPI CLEO_GetScriptInfoStr(CRunningScript* thread, bool currLineInfo, char* buf, DWORD bufSize) | Get formatted script information string |
Script Creation and Control
| CRunningScript* WINAPI CLEO_CreateCustomScript(CRunningScript* fromThread, const char* filePath, int label) | Create a new custom script |
| void WINAPI CLEO_TerminateScript(CRunningScript* thread) | Terminate a running script |
| CRunningScript* WINAPI CLEO_GetScriptByName(const char* threadName, BOOL standardScripts, BOOL customScripts, DWORD resultIndex = 0) | Find script by name (call repeatedly for multiple results) |
Parameter Handling
Reading Parameters
| DWORD WINAPI CLEO_GetIntOpcodeParam(CRunningScript* thread) | Read integer parameter and advance script |
| float WINAPI CLEO_GetFloatOpcodeParam(CRunningScript* thread) | Read float parameter and advance script |
| LPCSTR WINAPI CLEO_ReadStringOpcodeParam(CRunningScript* thread, char* buff = nullptr, int buffSize = 0) | Read string parameter into buffer (null-terminated) |
| void WINAPI CLEO_RetrieveOpcodeParams(CRunningScript* thread, int count) | Read multiple parameters into opcodeParams array |
Writing Parameters
| void WINAPI CLEO_SetIntOpcodeParam(CRunningScript* thread, DWORD value) | Write integer parameter |
| void WINAPI CLEO_SetFloatOpcodeParam(CRunningScript* thread, float value) | Write float parameter |
| void WINAPI CLEO_WriteStringOpcodeParam(CRunningScript* thread, const char* str) | Write string parameter |
Peeking Parameters (Non-advancing)
| DWORD WINAPI CLEO_PeekIntOpcodeParam(CRunningScript* thread) | Peek integer value without advancing script |
| float WINAPI CLEO_PeekFloatOpcodeParam(CRunningScript* thread) | Peek float value without advancing script |
Utility Functions
File System Functions
| void WINAPI CLEO_ResolvePath(CRunningScript* thread, char* inOutPath, DWORD pathMaxLen) | Convert virtual path to absolute file system path |
| StringList WINAPI CLEO_ListDirectory(CRunningScript* thread, const char* searchPath, BOOL listDirs, BOOL listFiles) | List directory contents (supports wildcards) |
| LPCSTR WINAPI CLEO_GetGameDirectory() | Get absolute game directory path |
| LPCSTR WINAPI CLEO_GetUserDirectory() | Get absolute user files directory path |
Other Utility Functions
| void WINAPI CLEO_Log(eLogLevel level, const char* msg) | Add message to CLEO log |
| void WINAPI CLEO_RegisterCallback(eCallbackId id, void* func) | Register a callback function |
| void WINAPI CLEO_UnregisterCallback(eCallbackId id, void* func) | Unregister a callback function |
| void WINAPI CLEO_StringListFree(StringList list) | Free resources used by StringList container |
Usage Examples
Registering a Custom Opcode
OpcodeResult __stdcall MyOpcodeHandler(CRunningScript* script) {
// Read parameters
int param1 = CLEO_GetIntOpcodeParam(script);
float param2 = CLEO_GetFloatOpcodeParam(script);
// Process...
// Set result
CLEO_SetIntOpcodeParam(script, result);
return OR_CONTINUE;
}
// Register the opcode
CLEO_RegisterOpcode(0x0DD0, MyOpcodeHandler);
Creating a Custom Script
CRunningScript* newScript = CLEO_CreateCustomScript(
parentScript,
"cleo:\\MyScript.cs",
0 // start label
);
if (newScript) {
// Script created successfully
}
Working with Callbacks
void WINAPI OnGameBegin(DWORD saveSlot) {
if (saveSlot == -1) {
// New game started
} else {
// Game loaded from save slot
}
}
// Register callback
CLEO_RegisterCallback(eCallbackId::GameBegin, OnGameBegin);
CLEO_Utils Helper Library
The CLEO_Utils.h header provides utility functions and macros to simplify CLEO plugin
development with error handling, parameter validation, and common operations.
Setup Requirements
To use CLEO_Utils.h in your CLEO plugin project, configure your build settings:
Additional Include Directories:
$(PLUGIN_SDK_DIR)\plugin_sa\
$(PLUGIN_SDK_DIR)\shared\game\
$(PLUGIN_SDK_DIR)\plugin_sa\game_sa\
Preprocessor Definitions:
GTASA
TARGET_NAME=R"($(TargetName))"
Logging and Error Handling
Basic Logging Macros
| TRACE(format, ...) | Log message to file (can be displayed on screen via DebugUtils.ini) |
| LOG_WARNING(script, format, ...) | Display warning on screen and log to file (not shown for legacy scripts) |
| SHOW_ERROR(format, ...) | Show message box and log to file |
| SHOW_ERROR_COMPAT(format, ...) | Show error with legacy mode compatibility tip |
Condition Result Macro
OPCODE_CONDITION_RESULT(value) // Set opcode's logical result
Opcode Parameter Macros
These macros simplify parameter handling in opcode implementations with automatic type validation and error handling. They expand to multiple lines, so cannot be used where single statements are expected (e.g., if conditions without braces).
Parameter Inspection
| OPCODE_PEEK_PARAM_TYPE() | Get next parameter type without advancing |
| OPCODE_PEEK_VARARG_COUNT() | Get count of remaining variable arguments |
| OPCODE_SKIP_PARAMS(count) | Skip X parameters |
| OPCODE_SKIP_VARARG_PARAMS() | Skip all remaining variable arguments |
Reading Input Parameters
All read macros perform type validation and suspend the script on error.
Basic Types:
OPCODE_READ_PARAM_BOOL() // Read boolean value
OPCODE_READ_PARAM_INT8() // Read signed 8-bit integer
OPCODE_READ_PARAM_UINT8() // Read unsigned 8-bit integer
OPCODE_READ_PARAM_INT16() // Read signed 16-bit integer
OPCODE_READ_PARAM_UINT16() // Read unsigned 16-bit integer
OPCODE_READ_PARAM_INT() // Read signed 32-bit integer
OPCODE_READ_PARAM_UINT() // Read unsigned 32-bit integer
OPCODE_READ_PARAM_FLOAT() // Read float value
OPCODE_READ_PARAM_ANY32() // Read any 32-bit value (int or float)
String Parameters:
OPCODE_READ_PARAM_STRING(varName)
// Creates: const char* varName pointing to null-terminated string
OPCODE_READ_PARAM_STRING_LEN(varName, maxLength)
// Creates: const char* varName with length clamped to maxLength
OPCODE_READ_PARAM_STRING_FORMATTED(varName)
// Reads format string and var-args
// Creates: char varName[] with formatted text
// Creates: char* varNameOk (nullptr if invalid)
OPCODE_READ_PARAMS_FORMATTED(format, varName)
// Uses provided format for var-args
// Creates: char varName[] with formatted text
// Creates: char* varNameOk (nullptr if invalid)
OPCODE_READ_PARAM_FILEPATH(varName)
// Creates: const char* varName with resolved and validated file path
Validated Handle Parameters:
OPCODE_READ_PARAM_PTR() // Read and validate memory pointer
OPCODE_READ_PARAM_OBJECT_HANDLE() // Read and validate object handle
OPCODE_READ_PARAM_PED_HANDLE() // Read and validate ped/actor handle
OPCODE_READ_PARAM_VEHICLE_HANDLE() // Read and validate vehicle handle
OPCODE_READ_PARAM_PLAYER_ID() // Read and validate player ID
Output Variable Parameters (for mixed param order):
OPCODE_READ_PARAM_OUTPUT_VAR_INT() // Get int* for later writing
OPCODE_READ_PARAM_OUTPUT_VAR_FLOAT() // Get float* for later writing
OPCODE_READ_PARAM_OUTPUT_VAR_ANY32() // Get SCRIPT_VAR* for later writing
OPCODE_READ_PARAM_OUTPUT_VAR_STRING() // Get StringParamBufferInfo for later writing
Writing Output Parameters
All write macros perform type validation and suspend the script on error.
OPCODE_WRITE_PARAM_BOOL(value)
OPCODE_WRITE_PARAM_INT8(value)
OPCODE_WRITE_PARAM_UINT8(value)
OPCODE_WRITE_PARAM_INT16(value)
OPCODE_WRITE_PARAM_UINT16(value)
OPCODE_WRITE_PARAM_INT(value)
OPCODE_WRITE_PARAM_UINT(value)
OPCODE_WRITE_PARAM_FLOAT(value)
OPCODE_WRITE_PARAM_ANY32(value)
OPCODE_WRITE_PARAM_STRING(value)
OPCODE_WRITE_PARAM_STRING_INFO(info, value) // Using StringParamBufferInfo
OPCODE_WRITE_PARAM_PTR(value)
String Utilities
String Manipulation Functions
| std::string StringPrintf(const char* format, ...) | Returns std::string; format string with printf-style arguments |
| bool StringStartsWith(const std::string_view str, const std::string_view prefix, bool caseSensitive = true) | Returns bool; check if string starts with prefix |
| bool StringEndsWith(const std::string_view str, const std::string_view suffix, bool caseSensitive = true) | Returns bool; check if string ends with suffix |
| void StringSplit(const std::string_view str, const std::string_view delimiters, std::vector<std::string>& output) | Split string by delimiters into vector |
| void StringRemoveFormatting(std::string& str) | Remove GTA text formatting sequences (e.g., ~r~, ~b~) |
| void StringToLower(std::string& str) | Convert string to lowercase |
| std::string ScriptInfoStr(CLEO::CRunningScript* thread) | Returns std::string; get formatted script information string |
File Path Utilities
Path Manipulation Functions
| void FilepathNormalize(std::string& path, bool normalizeCase = true) | Normalize path: collapse parent refs, fix separators, optionally lowercase |
| void FilepathRemoveParent(std::string& path, const std::string_view base) | Remove parent directory prefix from path |
| const std::string_view FilepathGetParent(const std::string_view str) | Returns std::string_view; get path without last element |
| bool FilepathIsSafe(CLEO::CRunningScript* thread, const char* path) | Returns bool; verify path is within game directories |
| std::string GetConfigFilename() | Returns std::string; get this plugin's config file path |
Validation Functions
Handle Validation
| bool IsObjectHandleValid(DWORD handle) | Returns bool; validate game object handle |
| bool IsPedHandleValid(DWORD handle) | Returns bool; validate character/ped handle |
| bool IsVehicleHandleValid(DWORD handle) | Returns bool; validate vehicle handle |
| bool IsPlayerIdValid(int id) | Returns bool; validate player ID (-1, 0, or 1) |
Script Version Check
| bool IsLegacyScript(CLEO::CRunningScript* thread) | Returns bool; check if script version is pre-CLEO 5 |
| bool PluginCheckCleoVersion() | Returns bool; verify CLEO version compatibility |
Memory Utilities
Memory Patching
| class MemPatch | Class for saving and restoring memory patches |
| MemPatch MemPatchJump(size_t position, void* jumpTarget) | Returns MemPatch; create JMP patch at position, returns original bytes |
| void* MemPatchCall(size_t position, void* newFunction) | Returns void*; create CALL patch at position, returns original target |
String List Creation
template<typename T> StringList CreateStringList(const T& container)
|
Convert container of strings to CLEO StringList |
Usage Examples with CLEO_Utils.h
Custom Opcode with Parameter Validation
OpcodeResult __stdcall opcode_CreateEffect(CRunningScript* thread)
{
// Read and validate parameters
auto pedHandle = OPCODE_READ_PARAM_PED_HANDLE();
auto effectId = OPCODE_READ_PARAM_INT();
auto duration = OPCODE_READ_PARAM_FLOAT();
OPCODE_READ_PARAM_STRING(effectName);
// Process the effect...
bool success = CreateEffect(pedHandle, effectId, duration, effectName);
// Set condition result
OPCODE_CONDITION_RESULT(success);
// Write output
OPCODE_WRITE_PARAM_INT(effectHandle);
return OR_CONTINUE;
}
Safe File Operations
OpcodeResult __stdcall opcode_ReadFile(CRunningScript* thread)
{
OPCODE_READ_PARAM_FILEPATH(filepath); // Automatically validated
auto* outputVar = OPCODE_READ_PARAM_OUTPUT_VAR_STRING();
if (FilepathIsSafe(thread, filepath))
{
std::string content = ReadFileContent(filepath);
OPCODE_WRITE_PARAM_STRING_INFO(outputVar, content.c_str());
}
else
{
LOG_WARNING(thread, "Unsafe file path: %s", filepath);
return thread->Suspend();
}
return OR_CONTINUE;
}
Formatted String Reading
OpcodeResult __stdcall opcode_PrintFormatted(CRunningScript* thread)
{
OPCODE_READ_PARAM_STRING_FORMATTED(message);
if (messageOk) // Automatically created by macro
{
DisplayMessage(message);
}
else
{
SHOW_ERROR("Invalid format string in script %s",
ScriptInfoStr(thread).c_str());
return thread->Suspend();
}
return OR_CONTINUE;
}
Notes
- CLEO 5 supports GTA SA 1.0 US only
- Use CLEO_ResolvePath for file operations to ensure ModLoader compatibility
- String buffers have a maximum length of 255 characters (MAX_STR_LEN)
- CLEO_Utils.h macros expand to multiple lines - use braces with if statements
- Memory addresses below 0x10000 are considered invalid (Windows reserved)