# How ScriptGlobal and ScriptLocal Differ for Accessing GTA Script Memory in YimMenuV2

> Understand the differences between ScriptGlobal and ScriptLocal for accessing GTA script memory in YimMenuV2. Learn how each class targets shared global or thread-specific variables effectively.

- Repository: [YimMenu/YimMenuV2](https://github.com/YimMenu/YimMenuV2)
- Tags: deep-dive
- Published: 2026-07-16

---

**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`](https://github.com/YimMenu/YimMenuV2/blob/main/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_Index` in [`src/game/gta/ScriptGlobal.hpp`](https://github.com/YimMenu/YimMenuV2/blob/main/src/game/gta/ScriptGlobal.hpp).
- **ScriptLocal**: Maintains both `void* m_Stack` and `int m_Index`, requiring the script thread to be resolved via `Scripts::FindScriptThread` before 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:

```lua
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`](https://github.com/YimMenu/YimMenuV2/blob/main/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:

```lua
-- 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:

```lua
-- 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 in [`src/game/gta/ScriptGlobal.hpp`](https://github.com/YimMenu/YimMenuV2/blob/main/src/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`](https://github.com/YimMenu/YimMenuV2/blob/main/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.