UTI Format (Item Blueprint)
The Item (.uti) blueprint serves as the central data model for all tangible loot, weapons, armor, and usable gear in the game. It defines how an item physically appears on characters, what custom properties or stat bonuses it applies through specific upgrade hierarchies, its intrinsic monetary cost, and exactly what its runtime state behaves like when dropped into the world map.
At a Glance
| Property | Value |
|---|---|
| Extension(s) | .uti |
| Magic Signature | UTI / V3.2 |
| Type | Item Blueprint |
| Rust Reference | View rakata_generics::Uti in Rustdocs |
Data Model Structure
Rakata maps the Item definition directly into the rakata_generics::Uti struct. To view the exhaustive binary schema and strict GFF field mappings, please refer to the Rustdocs for this struct, where each field is explicitly documented.
An Item breaks down into four main categories:
- Core Identity: The basic text strings that provide the item’s name and description, including both identified and unidentified states (e.g.,
TemplateResRef,LocName,Description). - Economic & Charge Mechanics: The value of the item, and the number of charges left for consumable abilities (e.g.,
Cost,Charges). - Visual Geometry (Appearance): Setting what the item looks like when dropped on the floor or equipped (e.g.,
ModelVariation,TextureVar). - Combat & Upgrade Properties (
PropertiesList): The stat buffs, damage modifiers, and abilities bound to the item, alongside slots for workbench upgrades.
- Model Validation:
rakata-lintchecks the data against engine constraints to prevent fatal runtime crashes.
Engine Audits & Decompilation
The following information documents the engine’s exact load sequence and field requirements for .uti files mapped from swkotor.exe.
(Decompilation logic for this section was entirely audited and verified via native Ghidra pipeline against swkotor.exe, explicitly pulling from the primary dispatcher CSWSItem::LoadDataFromGff at 0x0055fcd0.)
Structural Load Phasing
The engine processes an Item structurally across multi-pass capabilities mappings.
| Function | Size | Behavior |
|---|---|---|
LoadDataFromGff | – | The main parser that sets what the item is, how many charges it holds, and its descriptions. |
LoadItemPropertiesFromGff | – | Reads the special properties (like energy damage or stat boosts), splitting them into ‘useable’ abilities versus permanent buffs. |
LoadItem | – | The constructor that decides whether to load the item onto a character or leave it idle in an inventory. |
LoadFromTemplate | – | A fallback used when spawning an item dynamically from a script instead of off a character. |
SaveItem / SaveItemProperties | – | The opposite pipeline that writes the item into a save game, which notoriously forces the item to always be flagged as “Identified”. |
Core Structural Findings
The engine rigorously evaluates base-item mapping constraints from 2DA arrays and aggressively overrides improperly defined models.
| Engine Rule | Runtime Behavior |
|---|---|
| Description Cross-Swap | If either Description or DescIdentified is missing, the engine automatically duplicates the provided string into the missing field so item identification mechanics never crash the game. |
| Model Truncation | If an older tool incorrectly configures ModelVariation to 0, the engine forcefully bumps it to 1 upon load, ensuring the item always has visible geometry instead of rendering an invisible weapon or armor piece. |
| Model & Body Variation Hooks | The engine completely ignores the .uti’s BodyVariation field, opting instead to enforce the exact body_var value predefined in baseitems.2da. Additionally, TextureVar is unconditionally bypassed unless the item’s base type is strictly configured as Model Type 1. |
| Cost Generation Fallback | The physical Cost integer provided in the file is dead data. The engine strictly computes economic value actively via GetCost() calculations based on its properties, completely ignoring your defined value. |
| Identifier Enforcement | During explicit serializing via SaveItem (when the player creates a save game), the engine actively forces and hardcodes Identified to 1 unconditionally. |
| Property Capabilities | Item properties are structurally split into Active and Passive memory tables at load. The engine evaluates every PropertyName index: any ID strictly mapping to 10, 37, 46, or 53 (e.g., Cast Power, Trap) is actively hooked as a usable player ability, while all other integers are silently applied as passive stat modifiers. |
Legacy & Ignored Data
| Finding Type | Explanation |
|---|---|
| Superseded Legacy Fields | Directly supplying static Cost or BodyVariation values is a byproduct of older file versions; these remain inherently unused overhead compared to the physical runtime 2DA evaluation. |
| Passive Legacy Artifacts | General nodes left over from older tools (like TemplateResRef, Comment, PaletteID, and explicitly UpgradeLevel) are bypassed on load entirely. |
Linter Rules
These rules are documented for engine parity but are not yet implemented into rakata-lint/src/rules/.
- Dead Cost Fields: (Pending) Diagnoses static
.utifiles configured with explicitCostdeclarations tracking identically to dead data. - Model Truncation Safety: (Pending) Throws a validation error if
ModelVariationstatically rests at0to prevent runtime geometric wrapping to1. - Dead Body Overrides: (Pending) Flags redundant definitions of
BodyVariationto eliminatebaseitems.2daduplicate resolution. - Valid Capability Bounds: (Pending) Scans all properties directly ensuring
PropertyName,UpgradeType(0xFF), andUsesPerDay(0xFF) meet standard operational targets.