Wrack > General Discussions > Topic Details
Layla Nov 16, 2013 @ 6:41am
Wrack Map Format Reversed
Hi, for those that want to make map editors and converters, I figured out the map format in a couple of days. I'm working on an alternative map editor and converters for other map formats.

There may be typos but this is all correct.

One thing you should know is that strings are prefixed with a 2 byte short for the string size, followed by that number of characters.

4 byte header - "MMAP"
4 byte int - Map version

String - Map name
String - Storyboard name
String - Skybox name
String - Next map name

2 byte short - Par time
4 byte int - Par score
2 byte short - Quick play order

String - Author name
String - Music file name
String - Boss music file name
String - ambient sound file name

4 byte float - Ambient sound volume

1 byte bool - Fog enabled
1 byte char (#4) - RGBA fog colour (alpha is unused)

4 byte float - Fog start
4 byte float - Fog end

4 byte int - Map flags

4 byte int - Vertex count
4 byte int - Face count
4 byte int - Zone count
4 byte int - Ground count
4 byte int - Thing count

For every Vertex -
2 byte short - X position
2 byte short - Y position
2 byte short - Z position
4 byte float - Texture coord U
4 byte float - Texture coord V
4 byte float - Lightmap coord U
4 byte float - Lightmap coord V

For every Face -
4 byte int - Face vertex count
4 byte int (#num face vertices) - Face vertex indices, one index for every vertex in the face
4 byte int - Face flags
String - Texture file name
4 byte float - Rotation
4 byte float - X scale
4 byte float - Y scale
4 byte float - X offset
4 byte float - Y offset
1 byte bool - X flip
1 byte bool - Y flip
1 byte char - Texture plane axis type
1 byte char - Light
1 byte char (#4) - RGBA light colour
4 byte float - Friction

4 bytes - Unknown, unused in released maps

String - Action string
1 byte char - Activation type
1 byte char - Activated by
1 byte char - Tag

1 byte - Unknown, unsued in released maps

String (#5) - 5 argument strings

4 byte int - FX flags
1 byte char (#4) - RGBA fog colour (Saved as BGRA for some reason, alpha unused)
4 byte float - FX start
4 byte float - FX end

For every Zone -
4 byte int - Zone face count
4 byte int (#num zone faces) - Face ids, one int for every zone face
2 byte short - Type
2 byte short - Tag

For every Group -
4 byte int - Group face count
4 byte int (#num group faces) - Face ids, one int for every group face

For every Thing -
String - Thing name
4 byte int - Thing data length
1 byte char (#data length) - Data for the thing to serialize it

4 byte int - Map script data length
1 byte char (#script data length) - Bytes in the script file, if the data length is zero then there's no script

Collision Data:

1 byte bool - Determines if Octree is pre-built, data will follow if true.
Skip 2 bytes
2 byte short - x min bounds
Skip 2 bytes
2 byte short - y min bounds
Skip 2 bytes
2 byte short - z min bounds
Skip 2 bytes
2 byte short - x max bounds
Skip 2 bytes
2 byte short - y max bounds
Skip 2 bytes
2 byte short - z max bounds

Octree nodes saved recursively.
4 byte int - Node face count, max of 63.
4 byte int (#face count) - Face Id's.
1 byte bool - Subdivide the cell.

4 byte int - PNG data length for lightmap, zero for no lightmap
1 byte char (#PNG data length) - Bytes for the png file, this is the lightmap.

Here's a quickly made snippet of code that will read a Wrack map.

Here's screenshots of the start of my Wrack map editor

Hope this helps anyone!
Last edited by Layla; Nov 17, 2013 @ 7:27pm
< >
Showing 1-15 of 15 comments
decino Nov 16, 2013 @ 6:48am 
Woah, that is very useful! I was working on a Doom to Wrack map converter a year ago, but I postponed it due to the map format changing a few times. Thanks!
Layla Nov 16, 2013 @ 6:50am 
I'm going to be working on a Quake 3 map converter. I could also do a Source BSP converter but there's probably no use in it.

The cool thing is because lightmaps are baked, I can write any kind of lighting solver to get much crazier lighting than maps compiled in Wracked.
Last edited by Layla; Nov 16, 2013 @ 6:52am
decino Nov 16, 2013 @ 6:53am 
You're absolutely amazing. I'm definitely going to have fun with this. :)
Carnevil  [developer] Nov 16, 2013 @ 7:38am 
Oh wow, that's awesome! Nicely done! \o/

I can help a bit on the collision thing. The whole thing starts of with a bool of "are the nodes prebuilt (and if so, here they are)". If you just set that to "false", you can entirely skip that part afterwards without adding too terribly much to loading times. The map converter does this, for anyone who's converted maps of an older format.

Again, great stuff!
Layla Nov 16, 2013 @ 7:44am 
Awesome, the collision has had me baffled for a whole day, took me the whole day to even notice it was collision, I was just assuming it was to do with visibility.
Carnevil  [developer] Nov 16, 2013 @ 7:58am 
Yeah, it's exporting the octree nodes which are built recursively so it can definitely be quite an odd, variable thing! :)
Layla Nov 16, 2013 @ 12:37pm 
I think I'll have to leave collision for now. It's nice that the game will calculate that if it's missing but it would still be nice to support it to cut down on load times. If anyone figures it out let me know. Or if Carnevil wants to explain the structure of it ;) I can get the first 6 shorts which I assume are the bounds of the root node but then it gets really confusing.
FTr Nov 16, 2013 @ 1:13pm 
This is some great stuff, looking forward for the converters.
FDA Nov 16, 2013 @ 2:27pm 
Originally posted by Layla:
I could also do a Source BSP converter but there's probably no use in it.
Just a note, I would totally use a bsp converter just for kicks. There's a lot of maps I think would be funny to see in wrack.
Layla Nov 17, 2013 @ 4:41pm 
I've sort of worked out the structure of it but I'm still not sure how it represents an octree.

I read a byte which is either 0 or 1, followed by 4 bytes for face count, then 4 bytes per face for the face id's. What does the 0/1 represent and how to know when collision data has finished being read?

This is all the values I get from E1L4
Layla Nov 17, 2013 @ 7:15pm 
Alright I get it now. I wasn't thinking about it recursively. 0/1 is a bool to subdivide the cell.

Here's a quick snippet of how to read it, I'll add it to the OP soon. This doesn't do anything with the octree but it should skip the section correctly just before reading the lightmap.

decino Nov 22, 2013 @ 8:02pm 
Bumping with some Doom map converter progress. It can convert the linedefs for now at a static (64 units) height. More to come!

Doom's E1M1:

Doom 2's MAP29:

Plutonia's MAP32:
Last edited by decino; Nov 22, 2013 @ 8:09pm
Madame Écureuil Nov 24, 2013 @ 3:06am 
You know what to do now! (Convert The Ultimate Torment and Torture into Wrack.)

Also, does Wrack have a scripting system like ACS in ZDoom?
Carnevil  [developer] Nov 24, 2013 @ 5:43am 
Yep! :) There are far more scripting capabilities in Wrack, too, like being able to actually script monsters.
decino May 2, 2014 @ 5:03pm 
Bumping with a (sort of) working converter for Quake maps. Quake's geometry works fine, but Wrack doesn't like it due to the way vertices are placed. I'll keep working on it and will hopefully support entity and texture conversion soon.

Download here[bitbucket.org]
Source code[bitbucket.org]
Last edited by decino; May 2, 2014 @ 5:22pm
< >
Showing 1-15 of 15 comments
Per page: 15 30 50

Wrack > General Discussions > Topic Details