worldDir - themeldingwars/Documentation GitHub Wiki

These files are a listing of the worldMap tiles that make up the mini map / world map of a zone. They live next to the zone files as <zoneId>.worldDir.

010 Editor Template

Implementations

  • FauFau reads it

Format

Little endian. Strings are stored as a uint32 length including the null terminator, followed by the characters and that terminator.

The header and every tile are layers like the ones of the zone, without the marker: a uint32 layer id and a uint32 length. The header is layer 0, a tile is layer 100.

Header

Field Type Notes
layerId uint32 0, the header layer
headerLength uint32 Layer length, the size of the header not counting these first 8 bytes
magic char[4] WMAP
version int32 3 in the files we have
numTiles int32 Number of tiles that follow
isDataEmbedded uint8 See Embedded tile data
path string Build machine path the map was baked from, e.g. \\s-us-nfs-3\ToolsData\Environments\stabilization\BakedData\all_users\world
fileSize uint32 Size of the header plus all tile records, i.e. where the embedded data starts

Older descriptions of this file read numTiles as a single byte followed by an unknown int32. That happens to produce the right tile count for small maps because the count is little endian, but it is wrong, and it hides isDataEmbedded.

Tile

Field Type Notes
layerId uint32 100, the tile layer
tileLen uint32 Layer length, the size of the rest of this tile record, 61 + len(fileName)
fileName string e.g. 5_10_0000259802_opt.worldMap
dataOffset uint32 Offset of this tile's worldMap data, 0 when not embedded
dataLength uint32 Length of that data
cubemapId uint32 Cube face, the first part of the file name
zoomLvl uint32 Zoom level, the second part of the file name
entryId uint32 The third part of the file name
boundsMin float[3]
boundsMax float[3]
originX float X of the tile's corner
originY float Y of the tile's corner
size float Edge length of the tile

The three ids reproduce the file name exactly:

`${cubemapId}_${String(zoomLvl).padStart(2, '0')}_${String(entryId).padStart(10, '0')}_opt.worldMap`

so a .worldDir can be converted between the embedded and non-embedded forms without inventing names.

The nine floats are the bounds of the tile, then its origin and size, for example for a 1024 unit tile:

boundsMin (-512, -512, 0)   boundsMax (512, 512, 0)   origin (-512, -512)   size 1024

The worldMap header carries the same values, but in a different order: origin and size first, then the bounds. Older descriptions read both as three opaque vectors.

Embedded tile data

When isDataEmbedded is non-zero, the worldMap tiles are not separate files on disk. They are appended to the .worldDir itself, starting at fileSize, and each tile's dataOffset and dataLength slice its data out of the same buffer. Each slice is a complete GTNO worldMap node, byte for byte identical to what the standalone file would contain.

When isDataEmbedded is zero, dataOffset is 0 and the tiles are loaded from the fileName next to the .worldDir.

Sample output

From an older tool, reading 12.worldDir (field names as that tool printed them):

Header: Unknown: 0.00
 Unknown2: 97.00
 Magic: WMAP
 Version: 3.00
 NumChunkDefs: 5.00
 Unknown4: 0.00
 path: \\s-us-nfs-3\ToolsData\Environments\stabilization\BakedData\all_users\world
 Unknown5: 590.00

ChunkDef: Pos: (x: 100, y: 89)
		ChunkName: 5_10_0000259802_opt.worldMap
		Unknown: 0.00 Unknown2: 11,822.00
		ChunkName1: 5.00
		ChunkName2: 10.00
		ChunkName3: 259,802.00
		x2: -256.00  y2: -256.00  z2: 0.00
		x3: 256.00   y3: 256.00   z3: 0.00
		x4: -256.00  y4: -256.00  z4: 512.00

Mapping that onto the fields above: Unknown2: 97 is headerLength, NumChunkDefs plus Unknown4 are numTiles and isDataEmbedded, Unknown5: 590 is fileSize, x: 100 and y: 89 are layerId and tileLen, ChunkName1/2/3 are cubemapId, zoomLvl and entryId, and x2 to z4 are boundsMin, boundsMax, originX, originY and size.

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