GVT Format (Global Variable Table)
Description: The globalvars (GLOBALVARS.res) file is the campaign’s plot state (type GVT ): the flags and counters scripts read and set across the whole playthrough. It sits loose in the save folder, written at save time.
At a Glance
| Property | Value |
|---|---|
| Filename | GLOBALVARS.res |
| Magic Signature | GVT / V3.2 |
| Type | Global Variable Table |
| Rust Reference | Handled by rakata-save (mid-refactor). |
Data Model Structure
Globals come in four types, one for each kind of variable a script can stash between sessions. Each type has its own get/set accessor (the engine’s GetValueBoolean / SetValueBoolean, and the Number, Location, and String variants), so what a type is for is what shapes how it is stored and how many of it the engine keeps room for:
| Type | Holds | Cap | What scripts use it for |
|---|---|---|---|
| Boolean | a single bit | 900 | Plot switches and one-shot guards: has this happened? The most common kind of global. |
| Number | a single unsigned byte (0-255) | 500 | Small counters and quest-stage enumerations. It is a byte, not a 32-bit integer, so it cannot hold an arbitrary count. |
| Location | a position and orientation | 100 | A remembered spot to send, spawn, or move an object to later. |
| String | a short text value | 5 | A handful of named text tokens; scripts rarely need one. |
The caps are hard limits: any identifier past a type’s cap is dropped on load with a “won’t fit” log.
Each type pairs a catalogue list of names with a positional value block: the name of global i is Cat<Type> element i, and its value is position i of the matching Val<Type> block. The catalogue maps each value slot back to its name.
| Catalogue (names) | Value block | Encoding |
|---|---|---|
CatBoolean | ValBoolean | VOID, bit-packed. Boolean i is bit 7 - (i & 7) of byte i >> 3 (most-significant bit first). Block length is (count >> 3) + 1 bytes. |
CatNumber | ValNumber | VOID, one unsigned byte per number. Number i is byte i; values are 0-255. |
CatLocation | ValLocation | VOID, a fixed 2400-byte array of 100 slots of 24 bytes each. Location i is slot i; unused slots are zero, and the block is written whole. |
CatString | ValString | LIST, one struct per string carrying a String (CExoString). |
Each Cat* element is a struct with a Name (CExoString). Because the Val* blocks are positional, dropping or reordering a catalogue entry silently reassigns every later value.
Warning
There are four global types, not two. A model that handles only
CatNumber/CatBooleansilently drops everyLocationandStringglobal. They are simple to miss, but they are real campaign state that has to round-trip.
Each 24-byte location slot is a CScriptLocation: a position Vector followed by an orientation Vector, with no area reference in K1.
| Field | Type | Meaning |
|---|---|---|
Position | Vector (three float32, LE) | The stored point (X, Y, Z), bytes 0x00-0x0b. |
Orientation | Vector (three float32, LE) | The stored facing (X, Y, Z), bytes 0x0c-0x17. |
Engine Audits & Decompilation
Documented from Ghidra decompilation of swkotor.exe (K1 GOG build); see the Provenance Policy. The encoding, the per-type accessors, and the location layout are read from:
| Function | Address | Covers |
|---|---|---|
CSWGlobalVariableTable::WriteTable | 0x005299b0 | Value-block encoding on write |
CSWGlobalVariableTable::ReadTableWithCatalogue | 0x0052a280 | Encoding and per-type caps on read |
CSWGlobalVariableTable::GetValueBoolean | 0x00529110 | Boolean value read (the script get) |
CSWGlobalVariableTable::GetValueNumber | 0x00529240 | Number value read |
CSWGlobalVariableTable::GetValueLocation | 0x00529350 | Location value read (slot copy) |
CSWGlobalVariableTable::GetValueString | 0x00529460 | String value read |
CSWSObject::GetScriptLocation | 0x004cb7b0 | Location field order (position then orientation) |
Note
The script layer is not documented yet. These are the engine’s internal per-type accessors. The NCS/NSS-facing script functions (
GetGlobalBoolean/SetGlobalBooleanand theNumber/Location/Stringpairs) that call them are still to be mapped and documented.
Implemented Linter Rules (Rakata-Lint)
None yet. Documented here ahead of any dedicated rakata-lint rules.