Call of Duty 4: .MAP file structure

From COD Modding & Mapping Wiki
Revision as of 23:56, 15 October 2008 by Zeroy (talk | contribs) (1 revision)
Jump to navigation Jump to search

I will try to explain the .map file structure, which CoD4Radiant uses, in detail here. The article will be updated whenever I find more information. The .map files for CoD, CoDUO and CoD2 are almost identical to CoD4 map files.

Global Structure

The .map file structure is not that hard to figure. You can simply open it with Notepad and read what is written, it's not a binary file type.

The file globally consists of 2 parts, the header and the body. The header consists of 3 lines telling the editor what version the map is and something about flags (?). The body part is much more interesting, it contains a list of entities. Each entity, on it's turn, can hold (multiple) brushes and / or some key-value pairs. Each brush holds vertexes (a point in 3D), either directly or inside a mesh or a curve.

There is a difference between a brush holding vertexes and a brush holding a mesh or a curve (which on their turn hold vertexes). The former is a 'normal' brush, a box with 6 sides. The latter has just one side and is used for the terrain or a 'patch' (mesh is for terrain patches, curve for curve patches).

This is an example of an empty map:

iwmap 4
"000_Global" flags  active
"The Map" flags 
// entity 0
{
"classname" "worldspawn"
}

The first row holds the version (which is 4, Call of Duty 4 ;-)), the next 2 rows ... I have no idea honestly. Then we have a commented line (starts with '//') which does nothing but informing us entity number 0 starts here. The entity starts with the bracket (= '{') character, and on the last line you see it's also closed by the '}' character. Everything in between IS entity 0.

Within entity 0 we see a key / value pair. It simply says that the 'classname' (key) is 'worldspawn' (value).

If we take a look at mp_backlot's first entity's key / value pairs, we get this:

"contrastGain" "0.425"
"diffusefraction" "0.5"
"_color" ".8 .9 1"
"sunlight" "1"
"sundirection" "-50 -20 0"
"sundiffusecolor" ".9 0.88 .75"
"suncolor" "1 0.92 0.88"
"ambient" ".1"
"bouncefraction" ".7"
"classname" "worldspawn"

These define the worldspawn settings, the sun light / direction / colour and other (related) variables. This is only in the first entity, which holds all brushes, curves and meshes. Other entities can hold those too, if they are defined as function groups. The other entities are not visible in-game, and define spawn places for instance.

Brush

A brush is kept in an entity, an example:

iwmap 4
"000_Global" flags  active
"The Map" flags 
// entity 0
{
"classname" "worldspawn"
// brush 0
{
 ( 64 32 -8 ) ( 0 32 -8 )  ( 0 0 -8 )   me_woodplanks01 128 128 0 0 0 0 lightmap_gray 16384 16384 0 0 0 0
 ( 0 0 0 )    ( 0 32 0 )   ( 64 32 0 )  me_woodplanks01 128 128 0 0 0 0 lightmap_gray 16384 16384 0 0 0 0
 ( 0 0 56 )   ( 64 0 56 )  ( 64 0 -8 )  me_woodplanks01 128 128 0 0 0 0 lightmap_gray 16384 16384 0 0 0 0
 ( 64 0 56 )  ( 64 32 56 ) ( 64 32 -8 ) me_woodplanks01 128 128 0 0 0 0 lightmap_gray 16384 16384 0 0 0 0
 ( 64 64 56 ) ( 0 64 56 )  ( 0 64 -8 )  me_woodplanks01 128 128 0 0 0 0 lightmap_gray 16384 16384 0 0 0 0
 ( 0 32 56 )  ( 0 0 56 )   ( 0 0 -8 )   me_woodplanks01 128 128 0 0 0 0 lightmap_gray 16384 16384 0 0 0 0
}
}

This just defines one simple box... Also a brush starts and ends with those brackets, and inside we see the actual information. All 6 rows (= 6 sides!) have the same sort of information stored, so I will just discuss one row:

 ( 64 32 -8 ) ( 0 32 -8 ) ( 0 0 -8 ) me_woodplanks01 128 128 0 0 0 0 lightmap_gray 16384 16384 0 0 0 0
File:Call of Duty 4 articles map brush

Be aware that almost every value can be either an integer or a float, positive or negative, unless stated otherwise.

So, what do we see? 3 times 3 values, that could possible be some coordinates...a texture name obviously and a lot of other values. The first 3 times 3 values hold indeed coordinates, coordinates for vertexes. Each couple of 3 values is one vertex, x y and z value. We have 3 vertexes, so they make a triangle.

We have 6 of those rows, each row, respectively holds the bottom, top, front, right, rear and left side of a box.

The next value is what we expected, the texture name (do you see why texture names may not contain spaces?). The following 2 values (128 and 128) tell us in how many world units the texture fits. This means that if our brush is 128 by 128 world units big, it can hold exactly one texture tile, 256 x 128 and it holds 2 texture tiles (you see the full texture twice on that side). These values cannot be negative.

Next we have 4 zero's. The first two is a pair which defines how much a texture is shifted (first value is horizontal shift, second is vertical shift). Normally textures start tiling from point (0 0 0), but these values can change that. On top, bottom, front and rear sides horizontal is considered to be along the x-axis, for the left and right sides it's along the y-axis. For the top and bottom sides vertical is considered to be along the y-axis, but on the other sides it's along the z-axis.

The third zero of the four is the rotation the texture has. This is in degree. The last zero is unknown what function it has.

'lightmap_grey' simply tells us which lightmap texture is applied. By pressing 'Shift + L' in the editor you can change it. The next value pair is in fact the same as the 2 values after the texture name; the number of world units this texture takes to repeat. This is usually much higher then a normal texture. In CoD4 if you press S and change the sample size, you change these values (Sample Size x 1024).

The last four zero's are unknown what function they have.

A brush can also have a smoothing type applied, or be 'detailed' (not used by the portal-creation system when compiling). The following brush has lightmap_blue and smoothing_smooth for the top face, lightmap_green for the front face and is defined as a 'detail' brush.

'detail' could also be 'weaponClip' or 'nonColliding'. 'smoothing smoothing_smooth' can also be 'smoothing smoothing_smooth_other'. If nothing is stated explicitly, 'smoothing smoothing_hard' is implied.

// brush 0
{
  contents detail;
 ( 64 32 -8 ) ( 0 32 -8 ) ( 0 0 -8 ) me_woodplanks01 128 128 0 0 0 0 lightmap_gray 8192 8192 0 0 0 0
 ( 0 0 0 ) ( 0 32 0 ) ( 64 32 0 ) me_woodplanks01 128 128 0 0 0 0 lightmap_blue 16384 16384 0 0 0 0 smoothing smoothing_smooth
 ( 0 0 56 ) ( 64 0 56 ) ( 64 0 -8 ) me_woodplanks01 128 128 0 0 0 0 lightmap_green 16384 16384 0 0 0 0
 ( 64 0 56 ) ( 64 32 56 ) ( 64 32 -8 ) me_woodplanks01 128 128 0 0 0 0 lightmap_gray 8192 8192 0 0 0 0
 ( 64 64 56 ) ( 0 64 56 ) ( 0 64 -8 ) me_woodplanks01 128 128 0 0 0 0 lightmap_gray 8192 8192 0 0 0 0
 ( 0 32 56 ) ( 0 0 56 ) ( 0 0 -8 ) me_woodplanks01 128 128 0 0 0 0 lightmap_gray 8192 8192 0 0 0 0
}

Curve

// brush 0
 {
  curve
  {
  toolFlags;
   ch_concretewall03
   lightmap_gray
   3 3 16 8
   (
	v 0 0 0 t 0 -0 1 1
	v 0 32 0 t 0 -512 1 11
	v 0 64 0 t 0 -1024 1 11
   )
   (
	v 32 0 0 t 512 -0 7 1
	v 32 32 0 c 255 0 0 255 t 512 -512 7 11
	v 32 64 0 t 512 -1024 7 11
   )
   (
	v 64 0 16 t 1024 -0 13 1
	v 64 32 16 t 1024 -512 13 11
	v 64 64 16 t 1024 -1024 13 11
   )
  }
 }
File:Call of Duty 4 articles map curve

This is a curve brush, 3x3. 3 by 3 vertexes...9 in total. We have 9 rows with a 'v' in front, big chance those are vertexes. Also, before those 3 blocks, we see '3 3 16 8'. The two 3's refer to the number of vertexes, in width (the first) and in height (the second). Width and height purely refer to the object itself and has nothing to do with the X or Y axis. If the curve is rotated, the vertexes are modified, not the number of vertexes in width and height.

The '16' refers to the sample size, which has to do with the lightmap texture's repeat pattern (see Brush). The '8' has an unknown functionality.

Just before the row we just examined, we see the texture and lightmap texture's name, as well as a 'toolFlags;' line, which simply indicates it has flags...

The 3 blocks of vertexes. Each block (between '(' and ')') provides information for a column. After the 'v' we see 3 values, the x, y and z value. Then we see a 't', which indicates we'll get some texture parameters now. These parameters have to do with the positioning of the texture. The first value differs between the columns. So apparently it has to do with the width or the X-axis position of a texture. The value simply tells us which pixel (in width, obviously) should be displayed at that very vertex. If the value is over the texture's maximum width or beneath zero, one should repectively substract or add the texture's width till a value that fits between 0 and the texture's width is retrieved. The next value is the same, except for the height.

Between the 'v' (vertex) and the 't' (texture) values, we can also have 'c' (colour) values. This is only applied to the middle vertex, all other vertexes are assumed to be 'c 255 255 255 0'. The first 3 values are RGB values, from 0 till 255. And then we have an alpha value, 0 is transparent, 255 is opaque.

After the 't' values, we can also have 'f' values...this happens when we press Patch -> Turn Terrain Edges, then we get 'f 1'...I have no idea what this does.

Then we have 2 very mysterious values left, the last two for each vertex. After long investigation, it seemed they had to do with the lightmap texture. Just like with the texture's values just before, these seem to indicate what vertex what position of the texture holds. Sample size was 16, so that would mean if one vertex holds the values '16' or a multiply of that, it would hold the start of a new texture tile (or the end of course).

Just like with brushes, a curve can be detail / weaponClip / nonColliding aswell. The same line is used as with brushes, and it either replaces or comes before the line 'toolFlags;'. If the curve has 'smoothing smoothing_hard' / 'smoothing smoothing_smooth' / 'smoothing smoothing_smooth_other' applied, this is put after the lightmap texture name. 'smoothing smoothing_hard' is the default, but can also be stated explicitly.

Mesh

A mesh (aka. terrain patch) is exactly the same as a curve in the .MAP file, except that it says 'mesh' instead of 'curve'. In the editor there is a significant difference though, since meshes' follow exactly every vertex, while curves only follow the 'green' vertexes (often the corners...the even vertexes (0, 2, 4, ...)). Curves see the other vertexes as hints, and incline towards them. Also, meshes can have odd and even number of vertexes in width and height, while curves can only hold odd numbers (this has to do with the 'green' vertexes).

A sample of a mesh:

// brush 0
 {
  mesh
  {
   ch_concretewall03
   lightmap_cyan
   3 2 16 8
   (
	v 0 0 8 t 0 -0 0 0
	v 0 64 8 t 0 -512 0 -4
   )
   (
	v 32 0 8 t 256 -0 2 0
	v 32 64 8 t 256 -512 2 -4
   )
   (
	v 64 0 8 t 512 -0 4 0
	v 64 64 8 t 512 -512 4 -4
   )
  }
 }

Entity

There are several other entities possible, which define spawn places, global intermissions, function groups, models or prefabs. Function groups contain what is described above (in entity 0: brushes, curves or meshes). The other examples are simple key / value pairs, each pair on a row.

Global intermission:

// entity 1
{
"origin" "-104.0 -2214.0 174.0"
"angles" "0 94 0"
"classname" "mp_global_intermission"
}

Spawn place:

// entity 2
{
"origin" "-670.0 -2176.0 88.0"
"angles" "0 0 0"
"classname" "mp_tdm_spawn"
}

Prefab:

// entity 3
{
"angles" "0 180 0"
"origin" "-614.0 -1844.0 64.0"
"model" "prefabs/mp_backlot/bldg_appt02.map"
"classname" "misc_prefab"
}

Model:

// entity 53
{
"origin" "829.0 600.0 184.0"
"angles" "0 270 0"
"model" "me_corrugated_metal2x4"
"classname" "misc_model"
}

Dynamic model:

// entity 2344
{
"classname" "dyn_model"
"modelscale" "1.262592"
"model" "com_bottle2"
"angles" "0 105.919 0"
"type" "clutter"
"origin" "-149.0 -1724.5 58.0"
}

Function group:

// entity 2437
{
"classname" "func_group"
// brush 0
 {
  curve
  {
  contents nonColliding;
   me_wire_black
   lightmap_gray
   3 3 16 3
   (
	v 568 -810 308 t 0 0 35.5 -19.25
	v 568 -810 308 t 0 0 35.5 -19.25
	v 568 -810 310 t 0 -256 35.5 -19.375
   )
   (
	v 274 -810 184 t 5105.2788 0 17.125 -11.5
	v 274 -810 186 t 5105.2788 0 17.125 -11.625
	v 274 -810 186 t 5105.2788 -256 17.125 -11.625
   )
   (
	v 7 -810 306 t 9802.1172 0 0.4375 -19.125
	v 7 -810 306 t 9802.1172 0 0.4375 -19.125
	v 7 -810 308 t 9802.1172 -256 0.4375 -19.25
   )
  }
 }
// brush 1
 {
  curve
  {
  contents nonColliding;
   me_wire_black
   lightmap_gray
   3 3 16 3
   (
	v 568 -810 310 t 0 0 35.5 -19.375
	v 568 -810 308 t 0 -256 35.5 -19.25
	v 568 -810 308 t 0 -256 35.5 -19.25
   )
   (
	v 274 -810 186 t 5105.2788 0 17.125 -11.625
	v 274 -810 186 t 5105.2788 -256 17.125 -11.625
	v 274 -810 184 t 5105.2788 -256 17.125 -11.5
   )
   (
	v 7 -810 308 t 9802.1172 0 0.4375 -19.25
	v 7 -810 306 t 9802.1172 -256 0.4375 -19.125
	v 7 -810 306 t 9802.1172 -256 0.4375 -19.125
   )
  }
 }
}

A function group defines brushes that belong to each other. In the editor, when you select one of those brushes, you select the others as well. The are 'one brush' for an outsider, but they consist of separate brushes technically.

Physics

We also have physics_box and physics_cylinder:

// brush 0
  {
physics_box
    {
      1.000000 0.000000 0.000000 -0.000000 1.000000 0.000000 -0.000000 0.000000 1.000000 0.000000 0.000000 4.000000 64.000000 64.000000 4.000000
    }
  }
// brush 0
  {
physics_cylinder
    {
      0.000000 -0.000000 1.000000 0.000000 0.000001 4.000000 8.000000 64.028755
    }
  }

The last number is the radius, '8' is the height.

Footer

These are only my findings on this subject, if anything I described here is wrong, I would love to hear so. Also, if anyone knows what the functionality is of one of the following values, I would be very pleased:

Global structure

"000_Global" flags  active
"The Map" flags 

Brush

The fourth zero (after the x, y and z coordinates), and the last four zero's in this line:

( 64 32 -8 ) ( 0 32 -8 ) ( 0 0 -8 ) me_woodplanks01 128 128 0 0 0 0 lightmap_gray 16384 16384 0 0 0 0

Curve / Mesh

The '8' before the vertex blocks begin, the 1 after the 'f' per vertex:

// brush 0
 {
  curve
  {
  toolFlags;
   ch_concretewall03
   lightmap_gray
   3 3 16 8
   (
	v 0 0 0 t 0 -0 1 1 f 1
	v 0 32 0 t 0 -512 1 11 f 1
	v 0 64 0 t 0 -1024 1 11 f 1
   )
   (
	v 32 0 0 t 512 -0 7 1 f 1
	v 32 32 0 t 512 -512 7 11 f 1
	v 32 64 0 t 512 -1024 7 11 f 1
   )
   (
	v 64 0 16 t 1024 -0 13 1 f 1
	v 64 32 16 t 1024 -512 13 11 f 1
	v 64 64 16 t 1024 -1024 13 11 f 1
   )
  }
 }

Physics

Everything...actually.