The world format is fairly straightforward. It is divided up into 7 sections, each section follows one another in the file. The first section is the Header, the second section is the Tile Data, the third section is Chests, the fourth is Signs, the fifth is NPCs, the sixth section is the NPC names, and seventh and final section is the Verification.

I've detailed each section below.

Type Formats

The types used in the world file are below, all are stored little-endian.

Bool1Either 0 for false, or 1 for true
Byte1Unsigned 0 .. 255
Int162Signed -32,768 .. 32,767
Int324Signed -2,147,483,648 .. 2,147,483,647
String*Pascal string. First byte contains the length of the string.
Single4Single-precision float
Double8Double-precision float
Rect164 Int32s that form a rectangle (left, right, top, bottom)


The header contains general information about the world, including the map version it was created with, and various flags.

Some fields are only present in certain versions of the map. I've included the minimum map version for each field. If the current version is less than that, you should act as if that field doesn't exist.

Int320Map Version (currently 69)
String0World Name
Int320World ID
Rect0World Bounds
Int320World Height in Tiles
Int320World Width in Tiles
Byte63Moon Type
Int32[3]44Tree Type X Coordinates
Int32[4]44Tree Styles
Int32[3]60Cave Back X Coordinates
Int32[4]60Cave Back Styles
Int3260Ice Back Style
Int3261Jungle Back Style
Int3261Hell Back Style
Int320Spawn X
Int320Spawn Y
Double0World Surface Y
Double0Rock Layer Y
Double0Game Time
Bool0Day/Night (0 = night, 1 = day)
Int320Moon Phase
Bool0Blood Moon
Int320Dungeon X
Int320Dungeon Y
Bool56Crimson World
Bool0Killed Eye of Cthulu
Bool0Killed Eater of Worlds
Bool0Killed Skeletron
Bool66Killed Queen Bee
Bool44Killed The Destroyer
Bool44Killed The Twins
Bool44Killed Skeletron Prime
Bool44Killed Any Hardmode Boss
Bool64Killed Plantera
Bool64Killed Golem
Bool29Saved Goblin Tinkerer
Bool29Saved Wizard
Bool34Saved Mechanic
Bool29Defeated Goblin Invasion
Bool32Killed Clown
Bool37Defeated Frost Legion
Bool56Defeated Pirates
Bool0Broke a Shadow Orb
Bool0Meteor Spawned
Byte0Shadow Orbs broken mod 3
Int3223Altars Smashed
Bool23Hard Mode
Int320Goblin Invasion Delay
Int320Goblin Invasion Size
Int320Goblin Invasion Type
Double0Goblin Invasion X
Bool53Is Raining
Int3253Rain Time
Single53Max Rain
Int3254Tier 1 Ore ID
Int3254Tier 2 Ore ID
Int3254Tier 3 Ore ID
Byte55Tree Style
Byte55Corruption Style
Byte55Jungle Style
Byte60Snow Style
Byte60Hallow Style
Byte60Crimson Style
Byte60Desert Style
Byte60Ocean Style
Int3260Cloud Background
Int1662Number of Clouds
Single62Wind Speed

Tile Data

Immediately following the header is the tile data. The tile data is a little more complicated. Some fields are only present if previous booleans are true.

The tiles are stored column-first. So the first tile is at 0,0, the second tile is at 1,0. Also, in later versions, there is RLE compression, which runs vertically for the current column only.

Finally, some tile types are marked "Important", and contain texture coordinates, other tiles have their texture coordinates calculated at runtime. Which types are important or not is not stored in the wld document, instead it is up to the client to keep a list.

Bool0Tile Active
If Tile Active:
Byte0Tile Type
If Tile Type is Important:
Int160Texture U
Int160Texture V
Bool48Color Present
If Color Present:
Byte48Tile Color
Bool<26This field does not exist after version 25
Bool0Wall Present
If Wall Present:
Byte0Wall Type
Bool48Wall Color Present
If Wall Color Present:
Byte48Wall Color
Bool0Liquid Present
If Liquid Present:
Byte0Liquid Amount
Bool0Liquid is Lava
Bool51Liquid is Honey
Bool33Red Wire Present
Bool43Green Wire Present
Bool43Blue Wire Present
Bool41Half Tile
Byte49Tile Slope
Bool42Actuator Present
Bool42In Active
Int1625RLE Length

If RLE is present and greater than 0, you should copy the current tile and all of its information RLE times down. RLE will never be greater than the number of tiles you have left in the current column.


Following the tile data are the chests in the world. There are always 1,000 entries in this table.

Bool0Chest Present
If Chest Present:
Int320Chest X
Int320Chest Y
Item[20]58Extra Items

The format for each Item is:

Byte59Stack High Byte
If Stack is greater than 0:
String<38Item Name
Int3238Item ID
Byte36Item Prefix ID


Following the chests are the signs. There are always 1,000 entries in this table.

Bool0Sign Present
If Sign Present:
String0Sign Text
Int320Sign X
Int320Sign Y


Following the signs are the NPCs. The NPC list is different from the chests and the signs, since there aren't a fixed number of them. Instead you loop until you find the first Inactive NPC.
Bool0NPC Active
If NPC Active:
String0NPC Type Name
Single0NPC X
Single0NPC Y
Bool0Is Homeless
Int320NPC Home X
Int320NPC Home Y

NPC Names

Following the NPCs are the NPC names.

String31Merchant Name
String31Nurse Name
String31Arms Dealer Name
String31Dryad Name
String31Guide Name
String31Clothier Name
String31Demolitionist Name
String31Goblin Tinkerer Name
String31Wizard Name
String34Mechanic Name
String65Truffle Name
String65Steampunker Name
String65Dye Trader Name
String65Party Girl Name
String65Cyborg Name
String65Painter Name
String65Witch Doctor Name
String65Pirate Name


At the very end, we have the verification section. This basically duplicates information we already loaded, just to be sure we read the previous part of the file correctly.

Bool7Success (must be true)
String7World Name (must match name in header)
Int327World ID (must match ID in the header)