BLANCO

Developer · blancodagoat.dev

← All parts

THE .Y* RESOURCE FAMILY

GTA V / RAGE file formats › Part 2

Every .y* resource type and version in one table, then the byte-level walk: RSC7 virtual pointers, the YTD texture dictionary and grcTexture offsets, the drawable and geometry tree, vertex declarations, and a safe texture repack strategy.

How to read the evidence markers on this page: no marker — verified from source or a primary spec, trust it. 🟡 — community reverse-engineering, widely used but never confirmed by Rockstar. 🔴 — folklore: repeated in tutorials, plausible, untested — verify before relying on it. ✅ — confirmed in-game on a real working pack. Full legend and corrections log.

3. The .y* resource family

All are RSC7 resource files: a 16-byte header plus a system (CPU) page and graphics (GPU) page, page-mapped, deflate-compressed.

RSC7 header:
  u32  ident       0x37435352  ("RSC7")
  u32  version     resource type version (the table below)
  u32  systemFlags page layout, system segment
  u32  gfxFlags    page layout, graphics segment

Page sizes are packed into the flags words as a base size (0x200 << (flags & 0xF)) times a sum of bit-weighted page counts (see RpfResourceFileEntry.GetSizeFromFlags()) if you need to compute them.

On the y prefix: the old claim that y means "win64/PC, consoles use x/w/c" is wrong. That's the GTA IV scheme (wdr = Windows, xdr = Xbox 360, cdr = PS3/Cell). GTA V uses .ydr on every platform. The y is just what RAGE moved to; it does not encode a platform.

For completeness, the full RAGE resource-extension prefix scheme (the first letter of an extension like ydr/ymap, across platforms and RAGE titles). GTA V ships everything under y:

PrefixPlatform
aandroid
cps3/psn
dxboxone/durango
iindependent (North-specific)
nnx64
ops4/orbis
pps5/prospero
sios
vvita/psp2
wwin32/x86/pc
xxbox360/xenon
ywin64/x64/linux (GTA V)
zxbox series x/s
Ext Resource Version What it is
.ydr Drawable 165 One model. Geometry, shaders, skeleton, optional embedded collision + LODs
.ydd Drawable Dictionary 165 Many drawables in one file (ped components, prop sets)
.yft Fragment 162 Breakable/physics object. Vehicles, destructible props. Drawable + damage/physics LODs
.ytd Texture Dictionary 13 DDS textures (DXT1/3/5, BC7, A8R8G8B8) + mipmaps
.ybn Static Bounds 43 Standalone collision
.ymap Map Data 2 Placement: what goes where
.ytyp Archetype Def 2 Definition: what a thing is
.ynv NavMesh 2 Ped pathfinding
.ynd Path Nodes 1 Vehicle path nodes
.yvr Vehicle Record 1 Recorded vehicle paths
.ywr Waypoint Record 1 Ped/vehicle waypoint routes
.ycd Clip Dictionary 46 Animations
.yed Expression Dict 25 Procedural bone expressions
.yld Cloth Dictionary 10 Cloth simulation data
.ypt Particle Effects 68 PTFX assets
.ymf Manifest 2 ytyp↔ymap dependency graph (_manifest.ymf)
.ymt Metadata varies PSO-encoded metadata
.ysc Script N/A Compiled RAGE script
.gxt2 Text N/A Localized strings
.awc Audio Wave N/A Audio container
.dat Various N/A cacheloader, gtxd, handling, .rel audio

ytyp vs ymap: the core distinction

  • ytyp = the class. "There exists an object prop_bench_01a, model X, bounds Y, LOD distance Z."
  • ymap = the instances. "Place prop_bench_01a at (150, -300, 20) rotated 45°."

You always need both. The ytyp must be loaded (DLC_ITYP_REQUEST or PERMANENT_ITYP_FILE) before any ymap referencing it.


18. Drawable & texture internals (.ydd / .ydr / .ytd)

§3 catalogues the .y* family; this section is the byte-level walk for the three you touch when editing clothing and textures. ✅ tier throughout: every struct offset below was confirmed against real GTA V files (freemode clothing .ydds and their .ytds) on this machine, and the parser that uses them round-trips those files under unit test.

RSC7 virtual pointers

Inside a decompressed resource, structures reference each other by absolute virtual address, not file offset. The address space is segmented:

Pointer looks likeLives inResolve
0x5xxxxxxxsystem (CPU) segmentptr & 0x0FFFFFFF = offset into system segment
0x6xxxxxxxgraphics (GPU) segmentptr & 0x0FFFFFFF = offset into graphics segment

Pointers are stored as u64 but the address always fits in the low u32. The decompressed payload is [system segment | graphics segment] back to back. Segment sizes come from the header's two flag words: a 0x200 << (flags & 0xF) base page size times a bit-weighted page-count sum (see the RSC7 header in §3).

A .y* file must be stored in the RPF as a resource entry, with its header intact. Store it as a binary entry and the game exits with ERR_SYS_INVALIDRESOURCE_5.

YTD: pgDictionary<grcTexture>

The system segment of a .ytd starts with the dictionary struct; the graphics segment holds nothing but compressed pixel data.

pgDictionary<grcTexture>  (at system segment offset 0)
  0x20  u64  name-hash list pointer   (u32 JOAAT hashes, sorted)
  0x28  u16  name-hash count
  0x30  u64  texture pointer list     (count × u64 → grcTexture)
  0x38  u16  texture count
grcTexture (64-bit layout)
  0x00  u64  VFT
  0x28  u64  NamePointer  → NUL-terminated char*
  0x50  u16  Width
  0x52  u16  Height
  0x58  u32  Format       FourCC: "DXT1", "DXT5", "ATI1", "ATI2", or a D3D format code
  0x5D  u8   Levels       (mip count)
  0x70  u64  DataPointer  → graphics segment, mip 0

DataPointer is at 0x70, not 0x60. 0x60 is a plausible guess that decodes to garbage on real files. If your texture rips come out as noise, this is the first offset to check.

FourCC → block format, and how much data mip 0 occupies:

FormatDecodes asMip-0 size
DXT1BC1 (RGB + 1-bit alpha)ceil(w/4)·ceil(h/4)·8
DXT3BC2ceil(w/4)·ceil(h/4)·16
DXT5BC3 (the clothing default)ceil(w/4)·ceil(h/4)·16
ATI1BC4 (single channel)ceil(w/4)·ceil(h/4)·8
ATI2BC5 (two channel, normal maps)ceil(w/4)·ceil(h/4)·16
A8R8G8B8 / A8B8G8R8uncompressed BGRA / RGBAw·h·4
A8 / L8alpha / luminancew·h

Mips follow mip 0 contiguously, each level ¼ the pixel count (block formats never shrink below one 4×4 block per dimension).

YDD/YDR: the drawable walk

A .ydr is a single Drawable at the resource root; a .ydd is a pgDictionary<Drawable> with the same list shape as the YTD dictionary (ptr @ 0x30, count @ 0x38). From a Drawable down to vertices:

Drawable
  +0x10  ShaderGroup pointer
  +0x50  DrawableModels High   → { u64 ptr → [DrawableModel...], u16 count @ +0x08 }
  +0x58  DrawableModels Med      (same shape)
  +0x60  DrawableModels Low
  +0x68  DrawableModels VLow

DrawableModel
  +0x08  geometries list pointer
  +0x10  geometry count

Geometry
  +0x18  VertexBuffer pointer
  +0x38  IndexBuffer pointer
  +0x58  IndicesCount   (u32)
  +0x60  VerticesCount  (u16)

VertexBuffer                        IndexBuffer
  +0x08  stride (u16)                 +0x08  count (u32)
  +0x10  data pointer                 +0x10  data pointer (u16 index array,
  +0x18  count (u32)                          triangle list)
  +0x30  declaration pointer

VertexDeclaration
  +0x00  channelFlags (u32)
  +0x04  stride (u16)
  +0x06  channel count (u8)
  +0x08  16 × 4-bit component type codes

Decoding the vertex declaration

channelFlags is a 16-bit presence mask over the fixed semantic order:

BitSemantic
0Position
1BlendWeights
2BlendIndices
3Normal
4 / 5Colour0 / Colour1
6TexCoord0 (the UV set)
7TexCoord1
14Tangent

Each present channel's byte offset within a vertex is the sum of the sizes of the present channels below it. Sizes come from the per-channel 4-bit type code via:

TYPE_SIZE = [2, 4, 4, 8, 8, 8, 12, 16, 4, 4, 4, 4, 4, 2, 2, 4]
            (index by type code; 1 = Half2, 5 = Float2, 6 = Float3,
             7 = Float4, 9 = UByte4 are the codes seen on real clothing)

Always assert Σ(channel sizes) == declared stride. The check is cheap and it catches a mis-read table before you ship garbage vertices. Real clothing example: channelFlags 0x40ff, 9 channels, 72-byte stride, TexCoord0 at +0x28 as 2×float32. Some meshes store UVs as Half2 instead, so handle the half-float path.

The V convention

GTA stores the texture V coordinate negated: real clothing data sits in v ∈ [-0.994, -0.007]. The correct texture row for a vertex is frac(v) under wrap addressing, which is why renderers must wrap, not clamp. A clamping sampler smears edge texels across the whole mesh (see the note in §16). If your UV display comes out vertically flipped, the fix is choosing frac(v) vs frac(-v) consistently in every place that maps UV to texture rows. Flipping only one consumer moves paint and decals to the wrong place while the display still looks right.

Safe texture repack

Editing pixels inside a .ytd without corrupting it does not require re-serializing the structs. This strategy stays structurally valid by construction:

  • Keep the system segment byte-identical, leaving every struct, pointer, dimension and format untouched.
  • Re-encode the edited RGBA to the texture's existing compressed format at its existing dimensions.
  • Overwrite mip 0 (and lower mips where the re-encode fits) at the texture's DataPointer in a copy of the graphics segment.
  • Re-serialize with the original header flags. Since no size changed, every offset and page count is still correct.

Because dimensions and format never change, all offsets and sizes are identical to the source file, and the game's structural gates (RSC7 magic + version, resource-not-binary) are satisfied by construction. Textures in formats you can't re-encode should be skipped with a warning rather than written approximately.

Provenance: offsets and the walk read from CodeWalker.Core and byte-verified against real GTA V clothing files; the decode/repack path is validated by round-trip unit tests over those files, including a repacked .ytd whose system segment stays bit-identical.