GFF Module and Area - OpenKotOR/PyKotor GitHub Wiki

GFF Types: Module and Area

ARE, GIT, and IFO are not separate binary dialects; they are three typed GFF resources that the Odyssey-family runtime consumes at different scopes. PyKotor models them as distinct generic readers, and the recovered GFF access layer in KotOR I, KotOR II, and Aurora follows the same label-driven pattern: resolve a field label, resolve the referenced field record, then decode typed payloads such as ResRef and CExoLocString. [ARE, GIT, IFO] GetFieldByLabel @ (/K1/k1_win_gog_swkotor.exe @ 0x00411630, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00623a40, /Other BioWare Engines/Aurora/nwmain.exe @ 0x14019fcc0) GetField @ (/K1/k1_win_gog_swkotor.exe @ 0x00410990, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x006238d0, /Other BioWare Engines/Aurora/nwmain.exe @ 0x14019fc20) ReadFieldCResRef @ (/K1/k1_win_gog_swkotor.exe @ 0x00411e10, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00624fa0, /Other BioWare Engines/Aurora/nwmain.exe @ 0x1401a12d0) ReadFieldCExoLocString @ (/K1/k1_win_gog_swkotor.exe @ 0x00411fd0, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00625240, /Other BioWare Engines/Aurora/nwmain.exe @ 0x1401a0f80)

For KotOR specifically, the practical split is narrower and safer to document than older one-file summaries suggest: ARE carries static area metadata, GIT carries per-area placed instances plus root audio integers, and IFO carries module-level entry configuration, area membership, and module script state. That scope split is explicit in the local schemas below; where retail loader visibility differs across binaries, the prose calls that out instead of pretending every label is equally recovered everywhere. [are.py fields, git.py sections, ifo.py fields]

Contents


ARE (Area)

Part of the GFF File Format Documentation.

ARE is the static-area half of the KotOR area package. PyKotor's schema exposes lighting, fog, grass, weather, map, room, and script-hook fields, and the recovered retail CSWSArea::LoadAreaHeader routines in KotOR I and KotOR II visibly read scalar metadata first, then an Expansion_List, and then ARE script-hook labels through the shared GFF readers. [ARE field model, construct_are] LoadAreaHeader @ (/K1/k1_win_gog_swkotor.exe @ 0x00508c50, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00718a20) GetListCount @ (/K1/k1_win_gog_swkotor.exe @ 0x00411940, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00624970, /Other BioWare Engines/Aurora/nwmain.exe @ 0x1401a0370) ReadFieldCResRef @ (/K1/k1_win_gog_swkotor.exe @ 0x00411e10, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00624fa0, /Other BioWare Engines/Aurora/nwmain.exe @ 0x1401a12d0) ReadFieldCExoLocString @ (/K1/k1_win_gog_swkotor.exe @ 0x00411fd0, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00625240, /Other BioWare Engines/Aurora/nwmain.exe @ 0x1401a0f80)

The field-name visibility is not identical across builds. K1 preserves the labels OnHeartbeat, OnUserDefined, OnEnter, and OnExit directly in the recovered area loader; the current TSL recovery exposes OnHeartbeat and OnUserDefined clearly in the same loader block and then continues through additional ResRef reads with less helpful symbol text, so the stable engine-level claim here is that retail area loading consumes ARE hook ResRefs through the same typed GFF path rather than that every label survives equally in every disassembly. LoadAreaHeader @ (/K1/k1_win_gog_swkotor.exe @ 0x00508c50, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00718a20) ReadFieldCResRef @ (/K1/k1_win_gog_swkotor.exe @ 0x00411e10, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00624fa0, /Other BioWare Engines/Aurora/nwmain.exe @ 0x1401a12d0)

That means the safest description is still the obvious one: ARE carries environmental and area-scope metadata, while dynamic placement lives elsewhere. Associated resources often include:

Those resources use the usual resource resolution order.

For the original Aurora-facing specification, see Bioware Aurora Area File Format. For patching ARE data in installers, see TSLPatcher GFFList Syntax Guide; for general installer-side modding context, see HoloPatcher README for Mod Developers.

Related formats:

Loading uses the same resource resolution order.

PyKotor models areas through ARE, construct_are, read_are, and write_are, identifies them as GFFContent.ARE, and decodes them through the shared GFFBinaryReader.load pipeline; Holocron Toolset exposes the same fields in its are.py area editor. Other implementations keep ARE in the generic GFF path too, including reone's gff.cpp and gffreader.cpp, KotOR.js's GFFObject.ts, Kotor.NET's GFF.cs, and xoreos's Aurora pipeline.

Core Identity fields

These root fields are schema-derived from the current local ARE reader. construct_are acquires Version, Tag, Name, and Comments directly from the ARE root, while ID, Creator_ID, and Flags remain part of the broader optional/deprecated block that the local model preserves but does not treat as the core runtime area state. [construct_are root identity reads, construct_are deprecated root reads]

Field Type Description
Tag CExoString Unique area identifier
Name CExoLocString Area name (localized)
Comments CExoString Developer notes/documentation
Creator_ID UInt32 Toolset creator identifier
ID UInt32 Area ID field
Version UInt32 Area version field
Flags UInt32 Area flags field

Lighting & Sun

The local ARE schema stores the main lighting state as RGB integers plus two shadow controls. construct_are reads SunAmbientColor, SunDiffuseColor, and DynAmbientColor through Color.from_rgb_integer, while SunShadows and ShadowOpacity are acquired as scalar fields. [construct_are lighting reads, construct_are color conversion block]

Field Type Description
SunAmbientColor color Ambient light color RGB
SunDiffuseColor color Sun diffuse light color RGB
SunShadows byte Enable shadow rendering
ShadowOpacity byte Shadow opacity (0-255)
DynAmbientColor color Dynamic ambient light RGB

Fog Settings

Fog is also explicit in the local read path: SunFogOn defaults to 0, SunFogNear and SunFogFar default to 10000.0 when omitted, and SunFogColor is converted from the stored RGB integer payload. [construct_are fog reads, construct_are fog color conversion]

Field Type Description
SunFogOn byte Enable fog rendering
SunFogNear float Fog start distance (default 10000.0) [are.py L380]
SunFogFar float Fog end distance (default 10000.0) [are.py L381]
SunFogColor color Fog color RGB

Moon Lighting and Night Fields

The moon-lighting block remains in the schema and is preserved by the local reader, but it is grouped with the legacy/deprecated-style fields rather than the main ARE state. MoonFogNear and MoonFogFar use the same 10000.0 default pattern as the sun fog fields when absent. [construct_are moon-field reads]

Field Type Description
MoonAmbientColor color Moon ambient light color
MoonDiffuseColor color Moon diffuse light color
MoonFogOn byte Moon fog toggle
MoonFogNear float Moon fog start distance
MoonFogFar float Moon fog end distance
MoonFogColor color Moon fog color
MoonShadows byte Moon-shadow toggle
IsNight byte Night-state flag

Grass Rendering

Grass-related fields are read directly from the ARE root: Grass_TexName as a ResRef, the density/size/probability controls as scalars, and the ambient/diffuse/emissive colors through RGB conversion. The local reader treats Grass_Emissive as optional and KotOR II-specific. [construct_are grass scalar reads, construct_are grass color reads]

Field Type Description
Grass_TexName ResRef Grass texture name
Grass_Density float Grass blade density (0.0-1.0)
Grass_QuadSize float Size of grass patches
Grass_Ambient color Grass ambient color RGB
Grass_Diffuse color Grass diffuse color RGB
Grass_Emissive (KotOR2) color Grass emissive color RGB
Grass_Prob_LL float Spawn probability lower-left
Grass_Prob_LR float Spawn probability lower-right
Grass_Prob_UL float Spawn probability upper-left
Grass_Prob_UR float Spawn probability upper-right

Weather System (KotOR2)

The KotOR II weather block is schema-derived from the local reader: ChanceRain, ChanceSnow, and ChanceLightning are acquired as optional integers with 0 defaults when absent. [construct_are weather reads]

Field Type Description
ChanceRain (KotOR2) int32 Rain probability (0-100)
ChanceSnow (KotOR2) int32 Snow probability (0-100)
ChanceLightning (KotOR2) int32 Lightning probability (0-100)

Dirty/Dust Settings (KotOR2)

The dirty/dust block is likewise schema-derived from the current reader: each of the three layers stores an ARGB color plus size, formula, and function integers, all defaulting to 0 when missing. [construct_are dirty-field reads, construct_are dirty-color reads]

Field Type Description
DirtyARGBOne (KotOR2) UInt32 First dust color ARGB
DirtySizeOne (KotOR2) float First dust particle size
DirtyFormulaOne (KotOR2) int32 First dust formula type
DirtyFuncOne (KotOR2) int32 First dust function
DirtyARGBTwo (KotOR2) UInt32 Second dust color ARGB
DirtySizeTwo (KotOR2) float Second dust particle size
DirtyFormulaTwo (KotOR2) int32 Second dust formula type
DirtyFuncTwo (KotOR2) int32 Second dust function
DirtyARGBThree (KotOR2) UInt32 Third dust color ARGB
DirtySizeThree (KotOR2) float Third dust particle size
DirtyFormulaThre (KotOR2) int32 Third dust formula type
DirtyFuncThree (KotOR2) int32 Third dust function

Environment & Camera

The environment block mixes two different field families in the local schema: DefaultEnvMap, CameraStyle, AlphaTest, and WindPower are part of the primary read path, while LightingScheme remains in the legacy/deprecated-style group. AlphaTest defaults to 0.2 and WindPower is normalized into the local AREWindPower enum. [construct_are environment reads, construct_are alpha/wind reads, construct_are lighting scheme read]

Field Type Description
DefaultEnvMap ResRef Default environment map texture
CameraStyle int32 Camera behavior type
AlphaTest float Alpha testing threshold (default 0.2) [are.py L368, reone are.cpp L302]
WindPower int32 Wind strength for effects (AREWindPower: Still=0, Weak=1, Strong=2) [are.py L298, reone are.cpp L383]
LightingScheme int32 Lighting-scheme identifier

Area behavior flags

The area-behavior block is mostly scalar flag state in the local schema. construct_are reads Unescapable, DisableTransit, StealthXPEnabled, StealthXPLoss, and StealthXPMax as part of the main path, while DayNightCycle, LoadScreenID, NoRest, NoHangBack, PlayerOnly, and PlayerVsPlayer live in the broader preserved field set. [construct_are flag reads, construct_are preserved area flags]

Field Type Description
Unescapable byte Cannot use save/travel functions
DisableTransit byte Cannot travel to other modules
StealthXPEnabled byte Award stealth XP
StealthXPLoss int32 Stealth detection XP penalty
StealthXPMax int32 Maximum stealth XP per area
DayNightCycle byte Day/night-cycle toggle [are.py L421, reone are.cpp L309]
LoadScreenID UInt16 Loading screen to display [are.py L422, reone are.cpp L339]
NoRest byte No-rest area flag [are.py L423, reone are.cpp L359]
NoHangBack byte Hang-back behavior flag [are.py L424]
PlayerOnly byte Player-only area flag [are.py L425]
PlayerVsPlayer byte Player-versus-player flag [are.py L426]

Skill Check Modifiers

ModSpotCheck and ModListenCheck are preserved by the local reader as optional integer fields with 0 defaults, but they are part of the same deprecated-style group as the other legacy Aurora carryovers rather than the minimal KotOR area state. [construct_are skill-modifier reads]

Field Type Description
ModSpotCheck int32 Area awareness-skill modifier
ModListenCheck int32 Area listen-skill modifier

Script Hooks

The ARE script hooks are explicit in both the local schema and the recovered K1/TSL area loaders. construct_are reads OnEnter, OnExit, OnHeartbeat, and OnUserDefined as ResRefs with blank defaults, and the current retail loader recovery already shows those labels feeding the shared ReadFieldCResRef path in the area-header load. [construct_are hook reads, construct_are hook reads continuation] LoadAreaHeader @ (/K1/k1_win_gog_swkotor.exe @ 0x00508c50, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00718a20) ReadFieldCResRef @ (/K1/k1_win_gog_swkotor.exe @ 0x00411e10, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00624fa0, /Other BioWare Engines/Aurora/nwmain.exe @ 0x1401a12d0)

Field Type Description
OnEnter ResRef Fires when entering area
OnExit ResRef Fires when leaving area
OnHeartbeat ResRef Fires periodically
OnUserDefined ResRef Fires on user-defined events

Minimap coordinate system

The ARE file contains a Map struct that defines how the minimap texture (lbl_map<resname>) aligns with the world space walkmesh. This coordinate system allows the game to display the player's position on the minimap and render map notes at correct locations.

Map struct fields

Field Type Description
MapPt1X float First map point X coordinate (normalized 0.0-1.0)
MapPt1Y float First map point Y coordinate (normalized 0.0-1.0)
MapPt2X float Second map point X coordinate (normalized 0.0-1.0)
MapPt2Y float Second map point Y coordinate (normalized 0.0-1.0)
WorldPt1X float First world point X coordinate (world units)
WorldPt1Y float First world point Y coordinate (world units)
WorldPt2X float Second world point X coordinate (world units)
WorldPt2Y float Second world point Y coordinate (world units)
NorthAxis int32 North direction orientation (0-3)
MapZoom int32 Map zoom level
MapResX int32 Map texture resolution X dimension

These fields form two calibration pairs: two normalized map-space points and their matching world-space points, plus the NorthAxis flag that decides whether the transform is direct or axis-swapped. That is the same data shape PyKotor reads from construct_are, reone parses into ARE_Map, and reone copies into its live map object before doing coordinate conversion. [construct_are map reads, reone parseARE_Map, reone Map::loadProperties]

Coordinate transformation

reone's Map::getMapPosition() is the cleanest published implementation of the ARE map transform. For NorthAxis values 0 and 1, it scales world X and Y directly into map X and Y; for values 2 and 3, it swaps the axes before applying the same linear interpolation shape. [reone Map::getMapPosition direct case, reone Map::getMapPosition swapped case]

For NorthAxis 0 or 1 (PositiveY or NegativeY):

scaleX = (MapPt1X - MapPt2X) / (WorldPt1X - WorldPt2X)
scaleY = (MapPt1Y - MapPt2Y) / (WorldPt1Y - WorldPt2Y)
mapPos.x = (world.x - WorldPt1X) * scaleX + MapPt1X
mapPos.y = (world.y - WorldPt1Y) * scaleY + MapPt1Y

For NorthAxis 2 or 3 (PositiveX or NegativeX - swapped mapping):

scaleX = (MapPt1Y - MapPt2Y) / (WorldPt1X - WorldPt2X)
scaleY = (MapPt1X - MapPt2X) / (WorldPt1Y - WorldPt2Y)
mapPos.x = (world.y - WorldPt1Y) * scaleY + MapPt1X
mapPos.y = (world.x - WorldPt1X) * scaleX + MapPt1Y

Inverse transformation

For rendering the minimap texture in world space:

worldScaleX = (WorldPt1X - WorldPt2X) / (MapPt1X - MapPt2X)
worldScaleY = (WorldPt1Y - WorldPt2Y) / (MapPt1Y - MapPt2Y)
world.x = WorldPt1X + (mapPos.x - MapPt1X) * worldScaleX
world.y = WorldPt1Y + (mapPos.y - MapPt1Y) * worldScaleY

For texture origin (0,0) in world space:

originX = WorldPt1X - MapPt1X * worldScaleX
originY = WorldPt1Y - MapPt1Y * worldScaleY

NorthAxis values

Value Enum Description Coordinate Mapping
0 PositiveY +Y is north Direct X/Y mapping
1 NegativeY -Y is north Direct X/Y mapping
2 PositiveX +X is north Swapped: world.x --> map.y, world.y --> map.x
3 NegativeX -X is north Swapped: world.x --> map.y, world.y --> map.x

Map texture

reone loads the area minimap texture as lbl_map plus the area resref and pairs it with the player-arrow texture at render time. Holocron Toolset's walkmesh renderer takes the complementary editor view: it builds 2D paths from walkmesh faces and then draws textures with an explicit translate, rotate, and scale step on top of that projection. [reone Map::loadTextures, walkmesh renderer face build, walkmesh renderer image draw]

Implementation Notes

The evidence-backed implementation point here is simply that these values are float calibration data used to align a texture-space minimap with world-space area geometry. The page intentionally stops at that transform and renderer shape rather than prescribing extra editor heuristics that are not directly anchored in one of the cited code paths. [construct_are map reads, reone Map::getMapPosition, walkmesh renderer face build]

Rooms & Audio Zones

Rooms is another straightforward schema-derived list. PyKotor reads each row into ARERoom objects with RoomName, EnvAudio, AmbientScale, DisableWeather, and ForceRating, and reone parses the same members from the ARE GFF. [construct_are rooms read, reone parseARE_Rooms]

Field Type Description
Rooms List Room definitions for audio zones and minimap regions

Each room row contains RoomName, EnvAudio, AmbientScale, and, in the KotOR II-shaped schema, optional DisableWeather and ForceRating values. [construct_are rooms read, reone parseARE_Rooms]

Implementation Notes

PyKotor deserializes ARE fields through construct_are, and the evidence-backed part of the minimap discussion is now confined to the map struct shape, the linear transform used by reone, and the corresponding walkmesh-plus-texture renderer shape in Holocron Toolset. The page intentionally avoids extra editor-specific bug taxonomies or workflow advice that are not directly grounded in those cited code paths. [construct_are, reone Map::getMapPosition, walkmesh renderer image draw]

See also


Part of the GFF File Format Documentation.

GIT files are the dynamic companion to ARE: the local schema stores per-area instance lists for creatures, doors, placeables, triggers, waypoints, stores, encounters, sounds, and cameras, plus an AreaProperties struct for ambient-audio and music integers. The exact KotOR retail list-label reads still need a cleaner caller pass than the current ARE loader work, so the object-family split below is intentionally schema-derived, but the underlying consumption path is the same typed GFF machinery used across KotOR I, KotOR II, and Aurora. [GIT class and section layout, construct_git root reads] GetFieldByLabel @ (/K1/k1_win_gog_swkotor.exe @ 0x00411630, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00623a40, /Other BioWare Engines/Aurora/nwmain.exe @ 0x14019fcc0) GetListCount @ (/K1/k1_win_gog_swkotor.exe @ 0x00411940, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00624970, /Other BioWare Engines/Aurora/nwmain.exe @ 0x1401a0370) ReadFieldCResRef @ (/K1/k1_win_gog_swkotor.exe @ 0x00411e10, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00624fa0, /Other BioWare Engines/Aurora/nwmain.exe @ 0x1401a12d0)

PyKotor carries area instance state through GIT, its GITCreature / GITDoor / related subclasses, plus construct_git, read_git, and write_git, labels the resource as GFFContent.GIT, and parses it through GFFBinaryReader.load; Holocron Toolset mirrors that data in its git.py instance editor and related module-resource workflows. The same generic-GFF treatment appears in reone's gff.cpp and gffreader.cpp, KotOR.js's GFFObject.ts, Kotor.NET's GFF.cs, and xoreos's Aurora loader stack.

Root properties (ambient audio and music)

These integers are schema-derived from the AreaProperties nested struct inside the GIT root. PyKotor acquires that struct first and then reads AmbientSndDayVol, AmbientSndDay, EnvAudio, MusicDay, MusicBattle, and MusicDelay with 0 defaults when the struct or individual fields are absent, which is the narrow claim justified here. [construct_git AreaProperties reads]

Field Type Description
AmbientSndDay Int Day ambient sound ID
AmbientSndDayVol Int Day ambient volume (0-127)
AmbientSndNight Int Night ambient sound ID
AmbientSndNitVol Int Night ambient volume
EnvAudio Int Environment audio type
MusicBattle Int Battle music track ID
MusicDay Int Standard/exploration music ID
MusicNight Int Night music track ID
MusicDelay Int Delay before music starts (seconds)

PyKotor's current retail-oriented reader does not populate AmbientSndNight, AmbientSndNitVol, or MusicNight in construct_git, so those fields should be read here as schema members that appear in older format descriptions and sibling implementations, not as fields this specific local reader currently depends on during deserialization. [construct_git AreaProperties reads]

Instance Lists

GIT files carry multiple top-level instance lists, and PyKotor deserializes each one independently with blank ResRef, zero transform, or empty-list defaults when the list or fields are absent. The table below is therefore schema-derived from the actual list names consumed by construct_git, not from a fully recovered retail caller walk yet. [construct_git list iteration]

List field Contains Description
Creature List GITCreature Spawned NPCs and enemies
Door List GITDoor Placed doors
Placeable List GITPlaceable Containers, furniture, objects
Encounter List GITEncounter Encounter spawn zones
TriggerList GITTrigger Trigger volumes
WaypointList GITWaypoint Waypoint markers
StoreList GITStore Merchant vendors
SoundList GITSound Positional audio emitters
CameraList GITCamera Camera definitions

Across those lists, the repeated pattern is straightforward: most instance structs store a template ResRef, placement coordinates, and then a small set of per-instance overrides such as tag strings, bearings, link targets, or local payload structs like trigger geometry. [construct_git creature/door/placeable/store/trigger/waypoint reads]

GITCreature Instances

Creature rows are the simplest placement records in the file. The current reader acquires TemplateResRef, XPosition, YPosition, ZPosition, and the planar orientation pair, then derives the stored bearing from those orientation components. [construct_git creature reads]

Field Type Description
TemplateResRef ResRef UTC template to spawn
XPosition Float World X coordinate
YPosition Float World Y coordinate
ZPosition Float World Z coordinate

GITDoor Instances

Door instances extend the same placement pattern with module-link data and an optional tweak-color override. In the local reader, Door List rows acquire LinkedTo, LinkedToFlags, LinkedToModule, TransitionDestin, Bearing, placement coordinates, and an optional TweakColor gated by UseTweakColor. [construct_git door reads]

Field Type Description
LinkedToFlags Byte Transition flags
TransitionDestin CExoLocString Destination label (UI)
X, Y, Z Float position coordinates

GITPlaceable Instances

Placeable rows are simpler: the current reader acquires TemplateResRef, X, Y, Z, Bearing, and the same optional tweak-color pattern used by doors. [construct_git placeable reads]

Field Type Description
Bearing Float rotation angle
TweakColor DWord color tint
Hitpoints Short Current HP override
Useable Byte Can be used override

GITTrigger Instances

Trigger rows add module-transition linkage and local geometry. The current reader acquires TemplateResRef, Tag, LinkedTo, LinkedToFlags, LinkedToModule, TransitionDestin, placement coordinates, and then optionally walks a Geometry list whose rows carry PointX, PointY, and PointZ. [construct_git trigger reads]

Field Type Description
TemplateResRef ResRef UTT template
Tag CExoString Instance tag
TransitionDestin CExoLocString Transition label
LinkedToModule ResRef Destination module
LinkedTo CExoString Destination waypoint
LinkedToFlags Byte Transition flags
X, Y, Z Float Trigger position
XPosition, YPosition, ZPosition Float Position (alternate)
XOrientation, YOrientation, ZOrientation Float orientation
Geometry List Trigger volume vertices

GITWaypoint Instances

Waypoint rows combine the shared placement fields with waypoint-specific UI state. PyKotor reads LocalizedName, Tag, TemplateResRef, XPosition, YPosition, ZPosition, planar orientation, appearance, map-note flags, and an optional localized MapNote. [construct_git waypoint reads]

Field Type Description
TemplateResRef ResRef UTW template
Tag CExoString Waypoint identifier
Appearance DWord Waypoint appearance type
LinkedTo CExoString Linked waypoint tag
X, Y, Z Float position coordinates
XOrientation, YOrientation Float orientation
HasMapNote Byte Has map note
MapNote CExoLocString Map note text
MapNoteEnabled Byte Map note visible

GITEncounter Instances

Encounter rows are schema-derived from Encounter List: the local reader acquires a template ResRef, position, an optional Geometry list using X, Y, Z point fields, and an optional SpawnPointList with spawn coordinates plus a single Orientation float. [construct_git encounter reads]

Field Type Description
TemplateResRef ResRef UTE template
Tag CExoString Encounter identifier
X, Y, Z Float Spawn position
Geometry List Spawn zone boundary

GITStore Instances

Store rows are one of the clearer examples of GIT-as-instance-data: the local reader acquires a store ResRef, position, and the planar orientation pair, then derives the bearing exactly as it does for creature instances. [construct_git store reads]

Field Type Description
TemplateResRef ResRef UTM template
ResRef ResRef Store ResRef
Tag CExoString Store identifier
X, Y, Z Float Position (for UI, not physical)
XOrientation, YOrientation Float orientation

GITSound Instances

Sound rows are minimal in the current local reader: PyKotor acquires a TemplateResRef plus XPosition, YPosition, and ZPosition, leaving the richer sound-emitter schema to the broader format table and sibling implementations. [construct_git sound reads]

Field Type Description
TemplateResRef ResRef UTS template
Tag CExoString Sound identifier
X, Y, Z Float Emitter position
MaxDistance Float Audio falloff distance
MinDistance Float Full volume radius
RandomRangeX, RandomRangeY Float position randomization
Volume Byte Volume level (0-127)

GITCamera Instances

Camera rows are also explicit in the local schema: CameraList entries acquire CameraID, FieldOfView, Height, MicRange, Orientation, Position, and Pitch, which is enough to justify the table below without leaning on unsourced editor behavior claims. [construct_git camera reads]

Field Type Description
CameraID Int Camera identifier
FieldOfView Float Field of view (degrees)
Height Float Camera height
MicRange Float Audio capture range
Orientation Vector4 Camera rotation (quaternion)
Pitch Float Camera pitch angle
Position Vector3 Camera position

Implementation Notes

At the schema level, GIT is the instance layer that places and selectively overrides blueprint-backed objects, while ARE remains the static area-configuration layer. That division is visible directly in the local model types: construct_git builds per-instance rows around template ResRefs and placement/orientation data, whereas construct_are handles the area's persistent environmental configuration. [GIT model types and construct_git, construct_are]

See also


Part of the GFF File Format Documentation.

IFO is the module-scope companion to ARE and GIT. PyKotor's schema records Mod_Entry_Area, entry coordinates and facing, Mod_Area_list, and the module-wide Mod_On* script hooks as first-class fields, which is the safest level to document until the KotOR retail module-loader names are recovered with the same field-name visibility already available for ARE. [IFO class fields, construct_ifo] GetFieldByLabel @ (/K1/k1_win_gog_swkotor.exe @ 0x00411630, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00623a40, /Other BioWare Engines/Aurora/nwmain.exe @ 0x14019fcc0) ReadFieldCResRef @ (/K1/k1_win_gog_swkotor.exe @ 0x00411e10, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00624fa0, /Other BioWare Engines/Aurora/nwmain.exe @ 0x1401a12d0) ReadFieldCExoLocString @ (/K1/k1_win_gog_swkotor.exe @ 0x00411fd0, /TSL/k2_win_gog_aspyr_swkotor2.exe @ 0x00625240, /Other BioWare Engines/Aurora/nwmain.exe @ 0x1401a0f80)

PyKotor models module descriptors through IFO, construct_ifo, read_ifo, and write_ifo, tags them as GFFContent.IFO, and decodes them through the same shared GFFBinaryReader.load path that Holocron Toolset builds on for entry points, area lists, and module scripts in its getting-started, module-editor, and module-resources flows. Reone's gff.cpp and gffreader.cpp, KotOR.js's GFFObject.ts, Kotor.NET's GFF.cs, and xoreos's Aurora loader likewise treat IFO as a typed GFF root rather than a separate binary dialect.

Core Module Identity

These fields are schema-derived from the IFO root. PyKotor reads Mod_ID, Mod_VO_ID, Mod_Name, Mod_Tag, and the module entry configuration directly from the root struct, defaulting missing binary/string fields to empty values and missing localized strings to LocalizedString.from_invalid(). [construct_ifo root reads, IFO defaults]

Field Type Description
Mod_ID Void (16 bytes) Unique module identifier (GUID)
Mod_Tag CExoString Module tag identifier
Mod_Name CExoLocString Module name (localized)
Mod_Description CExoLocString Module description (localized)
Mod_Creator_ID UInt32 Toolset creator ID
Mod_Version UInt32 Module version number
Mod_VO_ID CExoString Voice-over folder name

Mod_Description, Mod_Creator_ID, and Mod_Version live in the same root schema but are part of the broader optional/deprecated-style block in the current reader rather than the minimum entry-state read path. [construct_ifo optional block]

Entry Configuration

The module entry block is one of the cleanest parts of the local IFO schema: Mod_Entry_Area is read as a ResRef, Mod_Entry_X/Y/Z are read as floats, and Mod_Entry_Dir_X/Y are combined into the stored facing angle. When both direction components are absent or zero, the local reader documents the observed-retail fallback as a forward (1, 0) entry vector. [construct_ifo entry reads]

Field Type Description
Mod_Entry_Area ResRef Starting area ResRef
Mod_Entry_X Float Entry X coordinate
Mod_Entry_Y Float Entry Y coordinate
Mod_Entry_Z Float Entry Z coordinate
Mod_Entry_Dir_X Float Entry direction X (facing)
Mod_Entry_Dir_Y Float Entry direction Y (facing)

Area List

Mod_Area_list is also schema-derived but precise in the local reader: PyKotor acquires the list, inspects only the first row during construction, and reads Area_Name from that row as the canonical area ResRef when present. The writer side always emits at least one Area_Name row, so the current local tooling model treats one explicit area reference as the minimum serialized shape. [construct_ifo area list read, dismantle_ifo area list write]

Field Type Description
Mod_Area_list List Areas in this module

The row structure relevant to current tooling is just Area_Name, stored as the referenced area ResRef. [construct_ifo area list read, reone IFO_Mod_Area_list and parseIFO_Mod_Area_list]

Expansion Pack Requirements

This block should stay at the schema level for now. PyKotor reads Expansion_Pack into ifo.expansion_id, and reone parses the same field into its generated IFO struct; that is the strongest claim currently supported here, while Mod_MinGameVer still reads as a format-convention field pending a better source-backed pass. [construct_ifo expansion read, reone IFO field layout, reone parseIFO]

Field Type Description
Expansion_Pack word Expansion-pack field
Mod_MinGameVer CExoString Minimum game version

Older format references often describe Expansion_Pack as a bitfield, but that interpretation should remain secondary here until it is tied to stronger runtime evidence. [construct_ifo expansion read, reone parseIFO]

Starting Movie & HAK files

These are straightforward root fields in both the local and sibling parsers. PyKotor reads Mod_Hak as a string and Mod_StartMovie as a ResRef, while reone parses the same two members into its generated IFO struct. [construct_ifo HAK/movie reads, reone IFO field layout, reone parseIFO]

Field Type Description
Mod_StartMovie ResRef Starting movie file
Mod_Hak CExoString Required HAK file list

The safer wording here is simply that IFO stores a starting-movie resref and a HAK-list string; specific launch semantics are left for a runtime audit. [construct_ifo HAK/movie reads]

Cache & XP Settings

This subsection needs one distinction that the older text blurred: PyKotor reads Mod_XPScale, but its current construct_ifo path does not preserve Mod_IsSaveGame on read. reone parses both fields, and PyKotor's writer emits Mod_IsSaveGame as 0 when constructing a fresh IFO. [construct_ifo XP read, dismantle_ifo savegame write, reone IFO field layout, reone parseIFO]

Field Type Description
Mod_IsSaveGame byte Module is from save file
Mod_XPScale byte Experience point multiplier (0-200%)

So Mod_IsSaveGame belongs here as a schema-visible field, but not as a value the current local reader fully round-trips. [construct_ifo XP read, dismantle_ifo savegame write, reone parseIFO]

Timekeeping Fields

These timing fields are still part of the active schema in both codebases even though the current module-entry evidence collected for this page does not depend on them. PyKotor reads them into dawn_hour, dusk_hour, time_scale, start_month, start_day, start_hour, and start_year, and reone parses the same members into its generated IFO struct. [construct_ifo time-field reads, reone IFO field layout, reone parseIFO]

Field Type Description
Mod_StartMonth UInt32 Module start month
Mod_StartDay UInt32 Module start day
Mod_StartHour UInt32 Module start hour
Mod_StartYear UInt32 Module start year
Mod_DawnHour byte Dawn start hour
Mod_DuskHour byte Dusk start hour
Mod_MinPerHour UInt32 Minutes per in-game hour

For now, these remain documented as schema-visible timing fields rather than as proven live day/night controls in KotOR retail. [construct_ifo time-field reads, reone parseIFO]

Module Script Hooks

The module-hook block is straightforward in the local reader: construct_ifo acquires the Mod_On* ResRef fields directly from the IFO root and defaults them to blank ResRefs when omitted. That is the evidence-backed claim here; anything more specific about exact retail dispatch timing still belongs in a later reverse-engineering pass. [construct_ifo hook reads]

Field Type Description
Mod_OnAcquirItem ResRef Fires when item acquired
Mod_OnActvtItem ResRef Fires when item activated/used
Mod_OnClientEntr ResRef Fires on player enter (multiplayer)
Mod_OnClientLeav ResRef Fires on player leave (multiplayer)
Mod_OnCutsnAbort ResRef Fires when cutscene aborted
Mod_OnHeartbeat ResRef Fires periodically
Mod_OnModLoad ResRef Fires when module finishes loading
Mod_OnModStart ResRef Fires after player spawned
Mod_OnPlrDeath ResRef Fires when player dies
Mod_OnPlrDying ResRef Fires when player HP reaches 0
Mod_OnPlrLvlUp ResRef Fires on level up
Mod_OnPlrRest ResRef Fires when player rests
Mod_OnSpawnBtnDn ResRef Fires on spawn button (multiplayer)
Mod_OnUnAqreItem ResRef Fires when item lost/sold
Mod_OnUsrDefined ResRef Fires on user-defined events

Implementation Notes

At the code level, IFO still fills the module-metadata and entry-selection role, while ARE and GIT supply the chosen area's static and dynamic data. reone's module loader makes that split explicit by parsing IFO first and then loading the target area's ARE and GIT together. [construct_ifo, construct_are, construct_git, reone Module::load and loadArea]

See also


PTH (Path)

PTH is the area path graph resource. PyKotor models it as a GFF-backed PTH object whose Path_Points rows store 2D coordinates plus an edge-count window into Path_Conections, and reone parses the same two lists before converting them into an adjacency list for runtime pathfinding. [PTH and construct_pth, reone PTH structs, reone parsePTH, reone Paths::loadPath]

In reone's area loader, that parsed path data is elevated into 3D by sampling walkmesh elevation and then handed to the pathfinder, which makes the narrow runtime claim here defensible: PTH is the coarse graph layer, while the walkmesh still supplies area elevation and collision context. [reone Area::loadPTH, reone Pathfinder::load]

Path points

Each Path_Points row stores a 2D waypoint plus the slice of the connection list that belongs to it. PyKotor reconstructs outgoing edges by reading Conections and First_Conection and then walking the Path_Conections list; reone's provider does the same when building Path::Point::adjPoints. [construct_pth, reone PTH_Path_Points, reone Paths::loadPath]

Field Type Description
Path_Points List List of 2D navigation nodes for this area

The row members are X, Y, Conections, and First_Conection. The misspelling is part of the on-disk schema and is preserved by both PyKotor and reone. [construct_pth, reone parsePTH_Path_Points]

Path connections

Path_Conections is the flat edge table referenced by those point rows. Both PyKotor and reone treat each row as a single destination index. [construct_pth, reone PTH_Path_Conections, reone parsePTH_Path_Conections]

Field Type Description
Path_Connections List Directed edges between path nodes

The only member on each row is Destination, which indexes another entry in Path_Points. [construct_pth, reone parsePTH_Path_Conections]

Notes

PyKotor explicitly treats missing Path_Points and Path_Conections lists as empty and defaults per-point coordinates and indices to 0.0 and 0 respectively when fields are absent. [PTH docstring and construct_pth]

The path graph itself is 2D on disk: PTH stores only X and Y, while reone derives per-node Z values later by testing walkmesh elevation before loading the graph into the pathfinder. [reone PTH_Path_Points, reone Area::loadPTH]

That separation is the important distinction from BWM: PTH supplies graph connectivity, while the walkmesh still supplies the physical surface the game samples against. [reone Area::loadPTH, reone Pathfinder::load]

See also

⚠️ **GitHub.com Fallback** ⚠️