How ScriptGlobal and ScriptLocal Differ for Accessing GTA Script Memory in YimMenuV2
ScriptGlobal and ScriptLocal are the two Lua-exposed classes for reading and writing GTA script memory, where ScriptGlobal targets shared global variables indexed by hash with runtime validation, while ScriptLocal targets thread-specific stack variables scoped to active script instances.
YimMenuV2 provides two distinct Lua-exposed classes for reading and writing native GTA script memory. Understanding the architectural differences between ScriptGlobal and ScriptLocal is essential for safe and effective modding, as each class handles validation, scope, and memory addressing differently according to the underlying C++ implementation in the YimMenu/YimMenuV2 repository.
What ScriptGlobal and ScriptLocal Represent
ScriptGlobal (Global Scope)
ScriptGlobal represents global variables stored in the game’s shared memory block. These globals are indexed by a numeric hash that remains consistent across every script instance. In src/game/gta/ScriptGlobal.hpp, the class stores only an index (std::size_t m_Index) and provides methods to validate and dereference this shared memory.
ScriptLocal (Thread-Local Scope)
ScriptLocal represents local variables that live on a specific script thread’s stack. Unlike globals, these are scoped to the script that created them and require locating the active thread before access. The implementation holds a pointer to the script’s stack (void* m_Stack) alongside an index (int m_Index), as defined in the corresponding header.
Key Technical Differences
Underlying C++ Implementation
The C++ implementations differ fundamentally in what they track:
- ScriptGlobal: Maintains only
std::size_t m_Indexinsrc/game/gta/ScriptGlobal.hpp. - ScriptLocal: Maintains both
void* m_Stackandint m_Index, requiring the script thread to be resolved viaScripts::FindScriptThreadbefore construction.
When creating instances in Lua, ScriptGlobal(hash) accepts the hash directly, while ScriptLocal(scriptHash, stackIndex) first locates the script thread and wraps the resulting stack pointer.
Safety and Validation Logic
Safety checks represent the most critical distinction between the two classes.
ScriptGlobal implements CanAccess(), which performs internal game-specific validation before dereferencing. This protects against out-of-range global access and must be checked explicitly:
local global = ScriptGlobal(0x8C4)
if global:can_access() then
local stars = global:get_int()
end
ScriptLocal performs validation at construction time. If Scripts::FindScriptThread fails to locate the target script, the constructor returns nil. Once a valid instance exists, the thread’s stack is assumed writable without additional runtime checks.
Memory Access Patterns
Both classes expose similar Lua APIs for reading and writing values, but their execution paths differ:
ScriptGlobal methods (GetInt, GetFloat, GetString, SetInt, etc.) always invoke CanAccess() before dereferencing via global.As<T*>. The implementation in src/game/scripting/libraries/ScriptGlobal.cpp ensures safety before every read or write operation.
ScriptLocal methods directly dereference the stack pointer (local.As<T*>) because the constructor already verified thread validity. Writes occur unconditionally, as the stack is assumed present once the thread is located.
Both support offset chaining via At(offset) and At(offset, size) for array-like or struct-like navigation, returning new instances pointing to different memory slots.
Practical Usage Examples
Accessing Global Variables
Use ScriptGlobal for game configuration values, persistent stats, or data that exists irrespective of which script is running:
-- Read wanted level from global memory
local wantedGlobal = ScriptGlobal(0x8C4)
if wantedGlobal:can_access() then
local stars = wantedGlobal:get_int()
print("Current wanted stars:", stars)
-- Modify the global value
wantedGlobal:set_int(5)
end
-- Navigate array-like globals using At()
local weapons = ScriptGlobal(0x1E6F)
local firstWeapon = weapons:at(0):get_int()
local secondWeapon = weapons:at(1):get_int()
Accessing Local Script Variables
Use ScriptLocal for temporary variables, function parameters, or data living only while a specific script thread is active:
-- Access local variable at index 2 in script 0x2D2B9B5C
local localVar = ScriptLocal(0x2D2B9B5C, 2)
if localVar then
local value = localVar:get_int()
localVar:set_float(3.14)
-- Access struct members via offset
local nextField = localVar:at(1)
nextField:set_int(100)
end
Summary
- ScriptGlobal accesses shared memory indexed by hash, requires explicit
can_access()validation, and stores only an index insrc/game/gta/ScriptGlobal.hpp. - ScriptLocal accesses thread-local stack memory, validates the script thread at construction via
Scripts::FindScriptThread, and stores both a stack pointer and index. - Safety: ScriptGlobal validates per-access; ScriptLocal validates once at instantiation.
- Use cases: Use ScriptGlobal for persistent game state; use ScriptLocal for script-specific temporary data.
- Offset handling: Both support
At()for array/struct navigation, but ScriptGlobal returns a new global offset while ScriptLocal returns a new stack position.
Frequently Asked Questions
What happens if I try to access an invalid ScriptGlobal?
If you attempt to read or write a ScriptGlobal without calling can_access() first, or if the validation fails, the operation risks crashing the game. Always wrap global access in if global:can_access() then blocks, as implemented in src/game/scripting/libraries/ScriptGlobal.cpp.
Can ScriptLocal access variables from any running script?
Yes, provided the script thread is active. The constructor calls Scripts::FindScriptThread to locate the target; if the script isn’t running, ScriptLocal.New returns nil. You must check for nil before dereferencing, as the pointer becomes invalid once the script thread terminates.
Which is safer to use for modding GTA Online?
ScriptGlobal includes explicit safety checks via CanAccess(), making it safer for arbitrary memory probing. ScriptLocal assumes validity after construction but requires the script to be running. For stability, prefer ScriptGlobal when modifying persistent game state, and only use ScriptLocal when you know the target script is active.
How do array offsets work in both classes?
Both classes provide At(offset) and At(offset, size) methods. In ScriptGlobal, this calculates a new global index for array-like structures. In ScriptLocal, this navigates the script’s stack by offset bytes, useful for accessing struct fields. Both return new instances of their respective types pointing to the calculated memory location.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →