MM2 Reference

Format

Introduction Format Vehicles Hud map Sky Dome Midnight Club

Structure

In a pseudo-C style structure, a PKG-file looks like this:

struct PKG { char[4] header = "PKG3" | "PKG2"; PKGFile[] files; } union PKGFile { PKG2File pkg2file; // If header == "PKG2" PKG3File pkg3file; // If header == "PKG3" } struct PKG2File { char[4] header = "FILE"; String name; // Name of this section PKGFileData data; // Format depends of name, see below } struct PKG3File { char[4] header = "FILE"; String name; // Name of this section long length; // Length of this PKGFile in bytes PKGFileData data; // Format depends of name, see below } struct String { unsigned byte length; // Number of bytes in this string including // the string terminator. char[length - 1] characters; // ASCII characters char terminator = '\0'; }

PKGFileData

The PKGFileData is different depending on the name of the PKGFile section. The following section describes the known chunks or files as they are called in MM2 terminology.

VL, L, M, H

PKGFileData sections whose name ends with one of "VL", "L", "M", "H" define geometry primitives. The name suffixes define the LOD, the level of detail, of the particular part of the object. A PKG-file can have any number of separate parts, some have special significance, espescially for vehicle models.

The suffixes themself stand for Very Low, Low, Medium and High respectively.

struct PKGFileData { long nSections; // Number of sections making up this LOD long nVerticesTot; // Total number of vertices in this LOD long nIndiciesTot; // Total number of indicies in this LOD long nSections2; // Repetition of the number of sections? // Highly unlikely, but I have no better suggestion at // this time long flags; // Flags defining what components are provided with // each vertex, see below PKGSection[nSections] sections; } struct PKGSection { ushort nStrips; // Number of geometry strips in this section ushort flags; // Unknown flags (Always 0 in MM2 PKGs) long shaderOffset; // Offset into the shader list of the requested // paintjob PKGStrip[nStrips] strips; } struct PKGStrip { long verticesPerFace; // Determines if the strips are quads or triangles, // have only seen 3 in this field though long nVertices; // Number of vertices in this strip PKGVertex[nVertices] vertices; long nIndices; // Number of indices making up the geometry strip ushort[nIndices] indices; } struct PKGVertex { Vertex3D coordinate; // If flags indicate coordinates Vector3D normal; // If flags indicate normals Vertex2D textureCoordinate; // If flags indicate texture coordinates } struct Vertex3D { float x; float y; float z; } struct Vector3D { float x; float y; float z; } struct Vertex2D { float x; float y; }

Description of the bits for the PKGFILEData.flags field:

Bit 1
Texture coordinates or coordinates
Bit 4
Normals
Bit 8
Coordinates or texture coordinates

All other bits are unknown at this time.

shaders

Each PKGSection of the geometry references a shader, a shader defines the colour of the facets. Each PKG-file has one PKGFileData section containing the definitions of all shaders used in the PKG. Within this section, shaders can be defined in one of two ways, either using floating point colour values or integer colour values. The shader defines ambient, diffuse, specular and emissive colours. The floating point shader also specifies the shininess used to calculate highlights. Each shader can also specify one texture map.

The shaders are organized in groups called paint jobs. When an object is placed in game, a certain paint job is requested, either by the INST, PATHSET or PSDL files for monuments and props or by user interaction for player vehicle models. Each paint job holds the same number of shaders, even if a particular shader is identical in several paint jobs. The index defined in the PKGSection is an index into the shader list of each paint job.

PKGFileData { long shaderType; // Bit 7: Shader type // Bit 0-6: Number of paint jobs long shadersPerPaintJob; PKGShader[Number of paint jobs * shadersPerPaintJob] shaders; } union PKGShader { FloatPKGShader floatShader; // If type is 0 IntPKGShader intShader; // If type is 1 } FloatPKGShader { String textureName; Color4f ambient; Color4f diffuse; Color4f specular; Color4f emissive; float shininess; } IntPKGShader { String textureName; Color4d ambient; Color4d diffuse; Color4d specular; Color4d emissive; } Color4f { float red; float green; float blue; float alpha; } Color4d { unsigned char red; unsigned char green; unsigned char blue; unsigned char alpha; }

offset

PKGFileData { Vector3D offset; // Have not tested, but could be an offset added to all // vertices in the object }

xref

A PKG can reference external objects stored in other PKGs, when rendering a PKG with external references, each object referenced will be rendered too. These objects are possibly breakable, meaning that they can be detached from the main object.

PKGFileData { long nReferences; Vector3D xAxis; Vector3D yAxis; Vector3D zAxis; Vector3D origin; char[] name; char terminator = 0x00; // Just to end the string char[] unknown0 = "max"; ushort[] unknown1 = {0, 0, 0, 0, 0, 0, 0}; }