Changes

Jump to navigation Jump to search
22,960 bytes added ,  15:45, 4 November 2022
→‎Reading the body: Added Encapsulation
Line 1: Line 1: −
==General information==
+
TrackMania '''.gbx files''' ([[GameBox]]) are generic container files that can contain everything from configuration to textures to track definitions. They consist of a header, a reference table and the body.
TrackMania gamebox files (*.gbx) are generic container files that can contain everything from configuration to textures to track definitions. They consist of a header, a reference table and the body.
     −
In old versions of TrackMania they used to be text files - nowadays they are binary files. Integers are stored in little endian order. The file body is often compressed (using LZO).
+
In old versions of TrackMania they used to be text files – nowadays they are binary files. Integers are stored in little-endian order. The file body is often compressed (using {{wp|Lempel–Ziv–Oberhumer|LZO}}).
   −
==Engines, classes, chunks==
+
== Engines, classes, chunks ==
 
A .gbx file more specifically stores the serialization of one or more class instances. There is one main instance, and optionally a number of auxiliary instances.
 
A .gbx file more specifically stores the serialization of one or more class instances. There is one main instance, and optionally a number of auxiliary instances.
   −
The serializable classes are organized into 16 ''engines''. Each class is also subdivided into ''chunks''. A class is then not serialized in one go, but rather as a series of chunks. This allows Nadeo to easily extend classes in new TrackMania versions: instead of having to define a new class they can simply add more chunks to an existing one, and have older versions ignore these new chunk types.
+
The serializable classes are organized into ''engines''. Each class is also subdivided into ''chunks''. A class is then not serialized in one go, but rather as a series of chunks. This allows Nadeo to easily extend classes in new TrackMania versions: instead of having to define a new class they can simply add more chunks to an existing one, and have older versions ignore these new chunk types.
   −
The data in a gbx file follows the pattern <chunk ID> <chunk data>. A ''chunk ID'' is a 32-bit number that identifies the engine, the class, and the chunk in that class. If you for example see the bytes <code>07 30 04 03</code> in the file, that would correspond to the integer 0x03043007, and be interpreted as follows:
+
The data in a .gbx file follows the pattern {{c|<chunk ID> <chunk data>}}. A ''chunk ID'' is a 32-bit number that identifies the engine, the class, and the chunk in that class. If you for example see the bytes <code>07 30 04 03</code> in the file, that would correspond to the integer 0x03043007, and be interpreted as follows:
    
  engine class chunk
 
  engine class chunk
Line 16: Line 15:  
All engines and classes are named; in this case, engine 3 is the Game engine, and class 043 in that engine is CGameCtnChallenge. Chunks do not have names.
 
All engines and classes are named; in this case, engine 3 is the Game engine, and class 043 in that engine is CGameCtnChallenge. Chunks do not have names.
   −
Apart from chunk ID's there are also ''class ID's'', which are just like chunk ID's except the chunk index part is ignored (and 0). For a complete overview of engines and classes, see [[Class ID's]].
+
Apart from chunk IDs there are also ''class IDs'', which are just like chunk IDs except the chunk index part is ignored (and 0). For a complete overview of engines and classes, see [[Class IDs]].
   −
==Header==
+
== Header ==
 
The header contains things like compression information and the class ID of the main class instance. The current version of the header also provides a few chunks of the main class that serve as meta information (e.g. the thumbnail of a challenge).
 
The header contains things like compression information and the class ID of the main class instance. The current version of the header also provides a few chunks of the main class that serve as meta information (e.g. the thumbnail of a challenge).
   Line 40: Line 39:  
** uint32 numNodes: the total number of class instances related to this gbx file. This includes the main instance, any local auxiliary instances, and any referenced external nodes/files. An internal list will be allocated with this number of entries; the main instance is at index 0.
 
** uint32 numNodes: the total number of class instances related to this gbx file. This includes the main instance, any local auxiliary instances, and any referenced external nodes/files. An internal list will be allocated with this number of entries; the main instance is at index 0.
   −
==Reference Table==
+
== Reference table ==
 
* uint32 numExternalNodes: the number of external nodes and files that this .gbx references. These come from other files located in the .gbx's [[PAK|.pak]] file. The references to these will be placed in the same list as the local nodes (see above). Both raw files (e.g. textures) and .gbx main instances can be referenced.
 
* uint32 numExternalNodes: the number of external nodes and files that this .gbx references. These come from other files located in the .gbx's [[PAK|.pak]] file. The references to these will be placed in the same list as the local nodes (see above). Both raw files (e.g. textures) and .gbx main instances can be referenced.
 
* if numExternalNodes > 0:
 
* if numExternalNodes > 0:
Line 61: Line 60:  
**** uint32 folderIndex: the depth-first index of the folder which the file is in. 0 means the base folder itself.
 
**** uint32 folderIndex: the depth-first index of the folder which the file is in. 0 means the base folder itself.
   −
==Body==
+
== Body ==
 
* if body is compressed:
 
* if body is compressed:
 
** uint32 uncompressedSize
 
** uint32 uncompressedSize
Line 69: Line 68:  
** byte data[]
 
** byte data[]
   −
==Reading the body==
+
== Reading the body ==
 
The file body contains further chunks of the main class instance, and may also contain auxiliary class instances. Reading the body is started by creating an in-memory instance of the class corresponding to the main class ID (instances are called ''nodes'' internally), and calling ReadNode on it:
 
The file body contains further chunks of the main class instance, and may also contain auxiliary class instances. Reading the body is started by creating an in-memory instance of the class corresponding to the main class ID (instances are called ''nodes'' internally), and calling ReadNode on it:
   −
  ReadNode()
+
  ReadNode()<ref>[[ManiaPlanet_internals#Object_system|CMwNod::Archive]]</ref>
 
  {
 
  {
     while(true)
+
     while (true)
 
     {
 
     {
         chunkID = ReadUInt32();
+
         chunkID = ReadUInt32();<ref>[[ManiaPlanet_internals#CClassicArchive|CClassicArchive::ReadNat32]]</ref>
         if(chunkID == 0xFACADE01)
+
         if (chunkID == 0xFACADE01) // no more chunks
 +
        {
 +
            OnNodLoaded();<ref>[[ManiaPlanet_internals#Object_system|CMwNod::OnNodLoaded]]</ref>
 
             return;
 
             return;
 +
        }
 +
 +
        chunkFlags = GetChunkInfo(chunkID);<ref>[[ManiaPlanet_internals#Object_system|CMwNod::GetChunkInfo]]</ref>
 
   
 
   
         chunkFlags = GetChunkFlags(chunkID);
+
         if (chunkFlags == 0xFACADE01 || (chunkFlags & 0x11) == 0x10)
        if(chunkFlags & 0x10)
   
         {
 
         {
 
             skip = ReadUInt32();
 
             skip = ReadUInt32();
 +
            if (skip != 0x534B4950) // "SKIP"
 +
            {
 +
                OnNodLoaded();
 +
                return;
 +
            }
 +
 
             chunkDataSize = ReadUInt32();
 
             chunkDataSize = ReadUInt32();
 +
            SkipData(chunkDataSize);<ref>[[ManiaPlanet_internals#CClassicArchive|CClassicArchive::SkipData]]</ref> // skip unknown or obsolete chunk
 
         }
 
         }
 
   
 
   
         ReadChunk(chunkID);
+
         if (chunkFlags != 0xFACADE01 && (chunkFlags & 0x11) != 0x10)
 +
        {
 +
            if (chunkFlags & 0x10) // skippable
 +
            {
 +
                skip = ReadUInt32();          // unused
 +
                chunkDataSize = ReadUInt32(); // unused
 +
            }
 +
 +
            ReadChunk(chunkID);<ref>[[ManiaPlanet_internals#Object_system|CMwNod::Chunk]]</ref> // read the chunk
 +
        }
 
     }
 
     }
 
  }
 
  }
   −
GetChunkFlags() doesn't read anything from the file; it provides loading flags for the specified chunk ID. The only important flag is whether or not the chunk is "skippable". If it is, the chunk ID is followed by an uint32 0x50494B53 ("SKIP", shows up as "PIKS" in the file due to little endian ordering) and an uint32 specifying the size of the chunk data. This allows older versions of TrackMania that don't know how to parse this chunk ID to skip over the chunk data and go to the next chunk. If the chunk is not skippable, the chunk data follows immediately after the chunk ID.
+
The code 0xFACADE01 is used here for two different purposes. As a dummy chunk ID (read from the file), it signifies the end of the chunk list for the current class. As a flag (returned by the function GetChunkInfo), it signifies that the passed chunk ID is unknown. GetChunkInfo() doesn't read anything from the file; it provides loading flags for the specified chunk ID. The flag 0x01 indicates that the chunk must be read. If this flag is not set, the chunk can be skipped (if possible). The second important flag is 0x10 and indicates whether the chunk is "skippable" or not. If it is, the chunk ID is followed by an uint32 0x50494B53 ("SKIP", shows up as "PIKS" in the file due to little-endian ordering) and an uint32 specifying the size of the chunk data. This allows older versions of TrackMania that don't know how to parse this chunk ID to skip over the chunk data and go to the next chunk. If the chunk is not skippable, the chunk data follows immediately after the chunk ID.
   −
A dummy chunk ID of 0xFACADE01 signifies the end of the chunk list for the current class.
+
The function OnNodLoaded() is used by some classes to prepare the read data (e.g., to make them compatible with newer versions of the engine).
    
Chunk data is not self-describing; the program itself has to know how to read each one. In fact, if your program doesn't know a specific chunk ID and the chunk is not skippable, you can't even tell how long the chunk is.
 
Chunk data is not self-describing; the program itself has to know how to read each one. In fact, if your program doesn't know a specific chunk ID and the chunk is not skippable, you can't even tell how long the chunk is.
Line 102: Line 121:  
* '''bool''': 32-bit little-endian integer that can be 0 or 1.
 
* '''bool''': 32-bit little-endian integer that can be 0 or 1.
   −
* '''byte''', '''uint16''', '''int32''', '''uint32''', '''uint64''', '''uint128''', '''float''': regular little endian encoding.
+
* '''byte''', '''uint16''', '''int32''', '''uint32''', '''uint64''', '''uint128''', '''float''': regular little-endian encoding.
   −
* '''vec2D''':
+
* '''vec2''':
 
** float x
 
** float x
 
** float y
 
** float y
   −
* '''vec3D''':
+
* '''vec3''':
 
** float x
 
** float x
 
** float y
 
** float y
Line 118: Line 137:  
** float b
 
** float b
   −
* '''string''':
+
* '''string''':<ref>[[ManiaPlanet_internals#CClassicArchive|CClassicArchive::DoString]]</ref>
 
** uint32 length
 
** uint32 length
** byte chars[length] (UTF8, older files sometimes with BOM, not zero-terminated)
+
** byte chars[length] ({{wp|UTF-8}}, older files sometimes with {{wp|Byte order mark|BOM}}, not zero-terminated)
   −
* '''lookbackstring''': a form of compression which allows to avoid repeating the same string multiple times. Everytime a new string is encountered, it is added to a string list, and from then on this list entry is referenced instead of repeating the string another time.
+
* '''lookbackstring''':<ref>[[ManiaPlanet_internals#Id|CMwId::Archive]]</ref> a form of compression which allows to avoid repeating the same string multiple times. Every time a new string is encountered, it is added to a string list, and from then on this list entry is referenced instead of repeating the string another time.
 
** if this is the first lookback string encountered:
 
** if this is the first lookback string encountered:
 
*** uint32 version (currently 3)
 
*** uint32 version (currently 3)
** uint32 index: bit 31 and 30 define the string type. If both bits are 0, the index is a [[ManiaPlanet_internals#Id|number]]. The actual index is bits 0-29. If it is 0, a new string follows (and will be added to the string list). If it is greater than one, use the string at stringlist [index - 1]. A value of -1 means there is no data provided (unassigned).
+
** uint32 index: bit 31 and 30 define the string type. If both bits are 0, the index is a [[ManiaPlanet_internals#Id|number]]. The actual index is represented by the bits 0-29. If this value is 0, a new string follows (and will be added to the string list). If it is greater than one, use the string at stringlist [index - 1]. If no data is provided (unassigned), the bits 30 and 31 indicate how this state is stored. If bit 31 is set, the string "Unassigned" is used, but if bit 30 is set, the value -1 is stored instead.
** if (index & 0xC0000000) != 0 and (index & 0x3FFFFFFF) == 0:
+
** If the bits 0 through 29 are 0 and bit 30 or 31 is 1:
 
*** string newString. Append to the string list.
 
*** string newString. Append to the string list.
   −
''Note'': the lookback string state is reset after each header chunk. The string list is cleared completely, and the next lookback string will again trigger the version number. If index represents a number (bits 30 and 31 not set), it describes the position inside a ''global'' string table. In most cases it concerns the ID of a collection. The correspondences used up to now are: 11 = 'Valley', 12 = 'Canyon', 17 = 'TMCommon', 202 = 'Storm', 299 = 'SMCommon', 10003 = 'Common'.
+
''Note'': the lookback string state is reset after each header chunk. The string list is cleared completely, and the next lookback string will again trigger the version number. If index represents a number (bits 30 and 31 not set), it describes the position inside a ''global'' string table. In most cases it concerns the [[Collection ID|ID of a collection]].
   −
* '''fileref''': path to an external file, e.g. a skin.
+
''Note'': Virtual Skipper 2 uses version 2 of the lookback strings. In this version, the string is always stored, the index always contains the position within the global name table, and the field with the version is also always present.
 +
 
 +
* '''meta''':<ref>[[ManiaPlanet_internals#Identifier|SGameCtnIdentifier::Archive]]</ref> contains [[ManiaPlanet_internals#Identifier|meta]] information like the track environment, time of day, and author.
 +
** lookbackstring id
 +
** lookbackstring collection
 +
** lookbackstring author
 +
 
 +
* '''fileref''':<ref>CSystemPackManager::ArchivePackDesc</ref> path to an external file, e.g. a skin.
 
** byte version (currently 3)
 
** byte version (currently 3)
 
** if version >= 3:
 
** if version >= 3:
Line 139: Line 165:  
*** string locatorUrl
 
*** string locatorUrl
   −
* '''meta''': contains meta information like the track environment, time of day, and author.
+
* '''noderef''':<ref>[[ManiaPlanet_internals#CSystemArchiveNod|CSystemArchiveNod::DoNodPtr]]</ref> a reference to an auxiliary class instance.
** lookbackstring field1
  −
** lookbackstring field2
  −
** lookbackstring author
  −
 
  −
* '''noderef''': a reference to an auxiliary class instance.
   
** uint32 index. if this is -1, the node reference is empty (null).
 
** uint32 index. if this is -1, the node reference is empty (null).
 
** if the index is >= 0 and the node at the index has not been read yet:
 
** if the index is >= 0 and the node at the index has not been read yet:
Line 150: Line 171:  
*** ReadNode()
 
*** ReadNode()
   −
''Note'': In case of a text format gbx file (marked by a 'T' in the header) all numbers and strings are stored as one line of ASCII text in each case. Every line ends with a carriage return-linefeed (<CR><LF>) combination (0x0D and 0x0A). A single <LF> is part of a string.
+
''Note'': In case of a text format .gbx file (marked by a 'T' in the header) all numbers and strings are stored as one line of ASCII text in each case. Every line ends with a carriage return-linefeed ({{c|<CR><LF>}}) combination (0x0D and 0x0A). A single {{c|<LF>}} is part of a string.
 +
 
 +
===Encapsulation===
 +
Encapsulation is a special kind of chunk behavior added in ManiaPlanet that handles lookbackstrings and noderefs differently.
 +
 
 +
* A new temporary lookbackstring list is created just for this chunk - the counting of strings starts from 1 again. However, the previous state of lookback strings is not reset.
 +
* An index of the noderef is not included and the node is not added to the node list. That list is not reset either.
 +
 
 +
It looks like this:
 +
 
 +
CSystemArchiveEncapsuledChunk::CSystemArchiveEncapsuledChunk();
 +
// ...
 +
CSystemArchiveEncapsuledChunk::~CSystemArchiveEncapsuledChunk();
 +
 
 +
In this range of code, you need to set up your binary reader to handle the two rules above.
 +
 
 +
Here is the list of chunks that use encapsulation:
 +
 
 +
* CGameCtnChallenge '''03043040''', '''03043041''', '''03043043''', '''03043044''', '''0304304E''', '''0304304F''' (version < 2), '''03043054''', '''03043058''' (version >= 1)
 +
* CGameCtnMacroBlockInfo '''0310D00B''', '''0310D011'''
 +
* CGamePlayerProfileChunk_GameScores '''03146000''', '''03146002''', '''03146004'''
 +
* CGamePlayerProfileChunk_ScriptPersistentTraits '''03170000'''
 +
 
 +
== Class descriptions ==
   −
==Class descriptions==
   
===CGameCtnChallenge (03 043 000)===
 
===CGameCtnChallenge (03 043 000)===
   Line 169: Line 212:  
         byte
 
         byte
 
     if version >= 4:
 
     if version >= 4:
         uint32 copperPrice
+
         uint32 cost (Copper price; since version 12: Display cost)
 
         if version >= 5:
 
         if version >= 5:
 
             bool multilap
 
             bool multilap
Line 195: Line 238:  
             5: (old)Rounds, 6: InProgress, 7: Campaign, 8: Multi, 9: Solo, 10: Site, 11: SoloNadeo, 12: MultiNadeo)
 
             5: (old)Rounds, 6: InProgress, 7: Campaign, 8: Multi, 9: Solo, 10: Site, 11: SoloNadeo, 12: MultiNadeo)
 
  if version >= 1:
 
  if version >= 1:
     bool locked (used by VirtualSkipper to lock the map parameter)
+
     bool locked (used by Virtual Skipper to lock the map parameters)
 
     string password (weak xor encryption, no longer used in newer track files; see 03043029)
 
     string password (weak xor encryption, no longer used in newer track files; see 03043029)
 
     if version >= 2:
 
     if version >= 2:
 
         meta decoration (timeOfDay, environment, envirAuthor) (decoration envir can be different than collection envir)
 
         meta decoration (timeOfDay, environment, envirAuthor) (decoration envir can be different than collection envir)
 
         if version >= 3:
 
         if version >= 3:
             vec2D mapOrigin
+
             vec2 mapOrigin
 
             if version >= 4:
 
             if version >= 4:
                 vec2D mapTarget
+
                 vec2 mapTarget
 
                 if version >= 5:
 
                 if version >= 5:
 
                     uint128
 
                     uint128
Line 253: Line 296:  
             5: (old)Rounds, 6: InProgress, 7: Campaign, 8: Multi, 9: Solo, 10: Site, 11: SoloNadeo, 12: MultiNadeo)
 
             5: (old)Rounds, 6: InProgress, 7: Campaign, 8: Multi, 9: Solo, 10: Site, 11: SoloNadeo, 12: MultiNadeo)
 
 
 +
'''03043012'''
 +
string
 +
 +
'''03043013'''
 +
ReadChunk(0x0304301F)
 +
 
'''03043014''' (skippable)
 
'''03043014''' (skippable)
 
  uint32
 
  uint32
  string password (old style password with weak xor encryption. this chunk is no longer used in newer track files, see 03043029)
+
  string password (old style password with weak xor encryption. This chunk is no longer used in newer track files; see 03043029)
 
 
 
'''03043017''' (skippable)
 
'''03043017''' (skippable)
Line 267: Line 316:  
 
 
'''03043018''' (skippable)
 
'''03043018''' (skippable)
  uint32
+
  bool
 
  uint32 numLaps
 
  uint32 numLaps
   Line 283: Line 332:  
  uint32 sizeY
 
  uint32 sizeY
 
  uint32 sizeZ
 
  uint32 sizeZ
  uint32 needUnlock
+
  bool needUnlock
  uint32 flagsAre32Bit
+
  if chunkId != 03043013:
 +
    uint32 version
 
   
 
   
 
  uint32 numBlocks
 
  uint32 numBlocks
Line 293: Line 343:  
     byte y
 
     byte y
 
     byte z
 
     byte z
     uint16/uint32 flags
+
     if version == 0:
 +
        uint16 flags
 +
    if version > 0:
 +
        uint32 flags
 
     if (flags == 0xFFFFFFFF)
 
     if (flags == 0xFFFFFFFF)
 
         continue (read the next block)
 
         continue (read the next block)
Line 301: Line 354:  
     if (flags & 0x100000)
 
     if (flags & 0x100000)
 
         noderef blockparameters
 
         noderef blockparameters
 +
 
''Note:'' blocks with flags 0xFFFFFFFF should be skipped, they aren't counted in the numBlocks.
 
''Note:'' blocks with flags 0xFFFFFFFF should be skipped, they aren't counted in the numBlocks.
   −
''Note:'' It is possible that additional blocks with flags 0xFFFFFFFF (Unassigned) follow after all other blocks.
+
''Note:'' It is possible that additional blocks with flags 0xFFFFFFFF (Unassigned) follow after all other blocks.
 
 
 
'''03043021'''
 
'''03043021'''
Line 317: Line 371:  
 
 
'''03043025'''
 
'''03043025'''
  vec2D mapCoordOrigin
+
  vec2 mapCoordOrigin
  vec2D mapCoordTarget
+
  vec2 mapCoordTarget
 
 
 
'''03043026'''
 
'''03043026'''
Line 324: Line 378:  
 
 
'''03043027'''
 
'''03043027'''
  uint32 provided
+
  bool archiveGmCamVal
  if provided != 0:
+
  if archiveGmCamVal:
 
     byte
 
     byte
     vec3D x 3
+
     GmMat3 (vec3 x 3)
     vec3D
+
     vec3
 
     float
 
     float
 
     float
 
     float
Line 342: Line 396:     
'''0304302A'''
 
'''0304302A'''
  uint32
+
  bool
    
'''0304303D''' (skippable)
 
'''0304303D''' (skippable)
 
  bool unknown
 
  bool unknown
 
  uint32 version
 
  uint32 version
 +
if version >= 5:
 +
    uint32 frames  // If version < 5 then frames = 1
 
  if version >= 2:
 
  if version >= 2:
     if version >= 4:
+
     for each frame:
 
         uint32 size
 
         uint32 size
         byte riff[size] // Avg lightmap webp file
+
         byte image[size]   // Image is JPEG/JFIF or WEBP/RIFF file format
    uint32 size
+
        if version >= 3:
    byte jfif[size]     // Intens/Avg lightmap jpeg file
+
            uint32 size
    if version == 3:
+
            byte image[size]
        uint32 size
+
        if version >= 6:
        byte jfif[size] // Intens lightmap jpeg file
+
            uint32 size
 +
            byte image[size]
 
     if size != 0:
 
     if size != 0:
 
         uint32 uncompressedSize
 
         uint32 uncompressedSize
 
         uint32 compressedSize
 
         uint32 compressedSize
         byte data[compressedSize]
+
         byte compressedData[compressedSize] // ZLIB compressed lightmap cache node
 +
 
 +
'''03043040''' (skippable) ''"items"''
 +
 
 +
''Note:'' This chunk has its own lookback string state (is encapsulated with CSystemArchiveEncapsuledChunk).
 +
 
 +
''Note:'' Version 5+ can have data that is based on the count of certain types of items in the item array. If you want to modify items in TM2020, you can come across issues when modifying the item array and it becomes rather difficult. This can be resolved by downgrading the version to 4. This downgrade should only affect item snapping - which is "useful" only when deleting items in the map editor.
 +
 
 +
''Note:'' The following information may not be 100% accurate.
 +
 
 +
* '''connectedItemPairs''': Array of AnchoredObjects index pairs where the first item (of pair) is the item that will delete the second item (of pair). Example: (87, 110) - item #87 will delete item #110, when #87 gets deleted.
 +
* '''snappedBlocks''': ''Values'' are ''indexes'' of the Blocks array (chunk 0x01F). -1 = snapped to an item and you should use the index of snappedItems.
 +
* '''snappedItems''': ''Values'' are ''indexes'' of the AnchoredObjects array (this chunk). -1 = snapped to a block and you should use the index of snappedBlocks.
 +
* '''snapItemGroups''': Separates item "deletion groups" via a simple number. Usual values are between 0 and 5. You can index these with itemSnapIndexes values.
 +
* '''itemSnapIndexes''': Uses the values above to connect them with the item list. ''Values'' are ''indexes'' of '''snappedBlocks'''/'''snappedItems''' arrays. Any index of this array corresponds to the same AnchoredObjects index, '''except -1''', which means the item is not snapped.
 +
 
 +
uint32 version
 +
uint32
 +
uint32 size
 +
uint32 (10)
 +
uint32 numItems
 +
for each item:
 +
    node item (CGameCtnAnchoredObject, direct node)
 +
if version >= 1 && version != 5:
 +
    uint32 connectedItemPairCount
 +
    uint2 connectedItemPairs[connectedItemPairCount] // 2 uint32 per element
 +
if version >= 5: // TM2020
 +
    uint32 snappedBlockCount
 +
    uint32 snappedBlocks[snappedBlockCount]
 +
    if version < 7:
 +
        uint32 snapItemGroupCount
 +
        uint32 snapItemGroups[snapItemGroupCount]
 +
    if version >= 6:
 +
        uint32 snappedItemCount
 +
        uint32 snappedItems[snappedItemCount]
 +
    if version >= 7:
 +
        uint32 snapItemGroupCount
 +
        uint32 snapItemGroups[snapItemGroupCount]
 +
    if version != 6:
 +
        uint32 size
 +
        uint32[size] // unknown atm
 +
    uint32 itemSnapIndexCount // should be the same as the item count itself
 +
    uint32 itemSnapIndexes[itemSnapIndexCount]
 +
 
 +
'''03043044''' (skippable)
 +
uint32 unknown (0)
 +
uint32 size
 +
uint32 classID
 +
uint32 version
 +
if version >= 2:
 +
    uint32 count (number of metadata records)
 +
    for each count:
 +
        string varName
 +
        uint32 varType
 +
        switch varType:
 +
            case EType_Boolean:
 +
                bool
 +
            case EType_Integer:
 +
                int32
 +
            case EType_Real:
 +
                float
 +
            case EType_Text:
 +
                string
 +
            case EType_Int2:
 +
                int32
 +
                int32
 +
            case EType_Int3:
 +
                int32
 +
                int32
 +
                int32
 +
            case EType_Vec2:
 +
                float
 +
                float
 +
            case EType_Vec3:
 +
                float
 +
                float
 +
                float
 +
            case EType_Array:
 +
                uint32 typeKey
 +
                uint32 typeValue
 +
                uint32 arrayElements
 +
                for each arrayElements
 +
                    switch typeKey:
 +
                        case EType_Boolean:
 +
                            bool
 +
                        case EType_Integer:
 +
                            int32
 +
                        case EType_Real:
 +
                            float
 +
                        case EType_Text:
 +
                            string
 +
                    switch typeValue:
 +
                        case EType_Boolean:
 +
                            bool
 +
                        case EType_Integer:
 +
                            int32
 +
                        case EType_Real:
 +
                            float
 +
                        case EType_Text:
 +
                            string
 +
                        case EType_Int2:
 +
                            int32
 +
                            int32
 +
                        case EType_Int3:
 +
                            int32
 +
                            int32
 +
                            int32
 +
                        case EType_Vec2:
 +
                            float
 +
                            float
 +
                        case EType_Vec3:
 +
                            float
 +
                            float
 +
                            float
 +
                        case EType_Array:
 +
                            recursively read multidimensional arrays
 +
 
 +
The variable type is to be interpreted as follows:
 +
enum eScriptType
 +
{
 +
    EType_Void = 0,
 +
    EType_Boolean,
 +
    EType_Integer,
 +
    EType_Real,
 +
    EType_Class,
 +
    EType_Text,
 +
    EType_Enum,
 +
    EType_Array,
 +
    EType_ParamArray,
 +
    EType_Vec2,
 +
    EType_Vec3,
 +
    EType_Int3,
 +
    EType_Iso4,
 +
    EType_Ident,
 +
    EType_Int2,
 +
    EType_Struct
 +
};
 +
Maniaplanet 4.1 has changed the way script types and values are written. The code now does the following:
 +
 
 +
* First write the list of all types (all types appear only once).
 +
* For each value, write the index of the type in the list, and then write the value.
 +
 
 +
Writing the types and values has not changed except for the addition of structures which are a plain list of members.
 +
 
 +
Also note that the indices are written in the following form:
 +
 
 +
* If the index is < 128, it is written directly into one byte (because this covers 99% of the cases).
 +
* Otherwise, it is written in the first 7 bits of the first byte and in the following 2 bytes, a total of 23 bits (7+8+8). The 8th bit of the first byte is set to 1.
 +
 
 +
Note that this scheme is also used to write string lengths.
 +
 
 +
'''03043054''' (skippable)
 +
 
 +
''Note:'' This chunk has its own lookback string state (is encapsulated with CSystemArchiveEncapsuledChunk).
 +
 
 +
uint32 version (1)
 +
uint32
 +
uint32 chunkSize
 +
uint32 itemCount (number of embedded items)
 +
meta items[itemCount]
 +
uint32 zipSize (embedded items ZIP file size)
 +
byte zipFile[zipSize]
 +
uint32 textureCount
 +
string textures[textureCount]
 +
 
 +
'''21080001''' ''"VskDesc"''
 +
 
 +
byte version
 +
if version < 1:
 +
    meta (trackUID, environment, mapAuthor)
 +
    string trackName
 +
bool unknown
 +
uin32 unknown
 +
if version < 1:
 +
    byte unknown
 +
byte unknown
 +
if version < 9:
 +
    byte boatName (0: Acc, 1 : Multi, 2 : Melges, 3 : OffShore)
 +
if version >= 9:
 +
    lookbackstring boat (separated by line feed: Boat name, website, boat ID)
 +
if version >= 12:
 +
    lookbackstring boatAuthor
 +
byte raceMode (0: Fleet Race, 1 : Match Race, 2 : Team Race)
 +
byte unknown
 +
byte windDirection (0: North, 1: NE, 2: East, 3: SE, 4: South, 5: SW, 6: West, 7: NW)
 +
byte windStrength (Force: windStrength + 3)
 +
byte weather (0: Sunny, 1: Cloudy, 2: Rainy, 3: Stormy)
 +
byte unknown
 +
byte startDelay (0: Immediate, 1: 1 Min, 2: 3 Min, 3: 5 Min, 4: 8 Min)
 +
uint32 startTime
 +
if version >= 2:
 +
    uint32 timeLimit
 +
    bool noPenalty
 +
    bool inflPenalty
 +
    bool finishFirst
 +
    if version >= 3:
 +
        byte nbAIs
 +
        if version >= 4:
 +
            float courseLength
 +
            if version == 4:
 +
                byte unknown
 +
            uint32 windShiftDuration
 +
            if version >= 5:
 +
                int32 windShiftAngle
 +
                byte unknown
 +
                if version == 6 || version == 7:
 +
                    bool unknown
 +
                    string unknown
 +
                if version >= 7:
 +
                    bool exactWind (Exact wind: !exactWind)
 +
                    if version >= 10:
 +
                        uint32 spawnPoints
 +
                        if version >= 11:
 +
                            byte aILevel (0: Easy, 1: Intermediate, 2: Expert, 3: Pro)
 +
                            if version >= 13:
 +
                                bool smallShifts
 +
                                if version >= 14:
 +
                                    bool noRules
 +
                                    bool startSailUp
    
===CGameCtnCollectorList (03 01B 000)===
 
===CGameCtnCollectorList (03 01B 000)===
    
'''0301B000'''
 
'''0301B000'''
  uint32 num
+
  uint32 archiveCount
  Item items[num]
+
  SCollectorStock archive[archiveCount]
     meta
+
     meta (blockName, collection, author)
     uint32
+
     uint32 numPieces
    
===CGameCtnChallengeParameters (03 05B 000)===
 
===CGameCtnChallengeParameters (03 05B 000)===
Line 389: Line 664:  
  string tip
 
  string tip
 
  string tip
 
  string tip
+
 
 
'''0305B002'''
 
'''0305B002'''
 
(all fields are ignored)
 
(all fields are ignored)
Line 408: Line 683:  
  uint32
 
  uint32
 
  uint32
 
  uint32
+
 
 
'''0305B003'''
 
'''0305B003'''
 
(all fields are ignored)
 
(all fields are ignored)
Line 428: Line 703:     
'''0305B005'''
 
'''0305B005'''
uint32 x 3 (ignored)
+
(all fields are ignored)
 +
uint32
 +
uint32
 +
 +
uint32
    
'''0305B006'''
 
'''0305B006'''
  uint32 num
+
  uint32 count
 
  uint32 items[count] (ignored)
 
  uint32 items[count] (ignored)
 +
 +
'''0305B007'''
 +
uint32 (ignored)
    
'''0305B008'''
 
'''0305B008'''
Line 449: Line 731:     
'''0305B00D'''
 
'''0305B00D'''
  uint32 (-1?)
+
  noderef raceValidateGhost (CGameCtnGhost) (usually -1)
   −
'''0305B00E'''
+
'''0305B00E''' (skippable)
(skippable)
+
  string mapType
  uint32
+
  string mapStyle
  uint32
   
  uint32
 
  uint32
   Line 472: Line 753:  
  fileref parentPackDesc
 
  fileref parentPackDesc
   −
===CGameWaypointSpecialProperty (0313B000) ===
+
'''03059003''' ''"TM2020"''
 +
uint32 version
 +
fileref secondaryPackDesc
 +
 
 +
===CGameWaypointSpecialProperty (03 13B 000) ===
 +
Mapped to the new GameData engine (2E) as class CGameWaypointSpecialProperty (2E009000).
 +
 
 
'''0313B000'''
 
'''0313B000'''
 
  uint32 version
 
  uint32 version
Line 481: Line 768:  
     string tag
 
     string tag
 
     uint32 order
 
     uint32 order
 +
 +
===CGameCtnAnchoredObject (03 101 000)===
 +
 +
'''03101002'''
 +
uint32 version
 +
meta (itemFile, collection, author)
 +
vec3 pitchYawRoll
 +
byte blockUnitX
 +
byte blockUnitY
 +
byte blockUnitZ
 +
lookbackstring anchorTreeId
 +
vec3 absolutePositionInMap
 +
CGameWaypointSpecialProperty waypointSpecialProperty (-1 if not a waypoint, otherwise direct node)
 +
if version < 5:
 +
    uint32
 +
if version >= 4:
 +
    uint16 flags
 +
    if version >= 5:
 +
        vec3 pivotPosition
 +
        if version >= 6:
 +
            float scale
 +
            if version >= 7:
 +
                if (flags & 4) == 4:
 +
                    fileRef packDesc
 +
                if version >= 8: // TM 2020
 +
                    vec3
 +
                    vec3
    
===CGameCtnReplayRecord (03 093 000)===
 
===CGameCtnReplayRecord (03 093 000)===
 
'''03093000''' ''"Version"''
 
'''03093000''' ''"Version"''
 
  uint32 version
 
  uint32 version
  if version >= 2:
+
  if version >= 3:
 
     meta (trackUID, environment, author)
 
     meta (trackUID, environment, author)
 
     uint32 time (ms)
 
     uint32 time (ms)
Line 510: Line 824:  
'''03093002''' (body)
 
'''03093002''' (body)
 
  uint32 size
 
  uint32 size
  byte GBX[size], the track the replay was recorded on
+
  byte GBX[size] (the track the replay was recorded on)
    
'''03093007''' (skippable)
 
'''03093007''' (skippable)
Line 557: Line 871:     
A sample record looks as follows:
 
A sample record looks as follows:
  vec3D position
+
  vec3 position
 
  uint16 angle      (0..0xFFFF -> 0..pi)
 
  uint16 angle      (0..0xFFFF -> 0..pi)
 
  int16 axisHeading (-0x8000..0x7FFF -> -pi..pi)
 
  int16 axisHeading (-0x8000..0x7FFF -> -pi..pi)
Line 567: Line 881:     
The rotation of the car is calculated as a quaternion.
 
The rotation of the car is calculated as a quaternion.
* The real part of the quaternion is calculated as cos(angle) which corresponds to a rotation of 2*angle around the rotation axis.
+
* The real part of the quaternion is calculated as {{c|cos(angle)}} which corresponds to a rotation of {{c|2*angle}} around the rotation axis.
* The imaginary part of the quaternion (the rotation axis) is calculated as the vector (sin(angle)*cos(axisPitch)*cos(axisHeading), sin(angle)*cos(axisPitch)*sin(axisHeading), sin(angle)*sin(axisPitch)).
+
* The imaginary part of the quaternion (the rotation axis) is calculated as the vector {{c|(sin(angle)*cos(axisPitch)*cos(axisHeading), sin(angle)*cos(axisPitch)*sin(axisHeading), sin(angle)*sin(axisPitch))}}.
 
You can [http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Conversion_to_and_from_the_matrix_representation convert this quaternion to a transform matrix].
 
You can [http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Conversion_to_and_from_the_matrix_representation convert this quaternion to a transform matrix].
   −
The velocity vector (direction and speed of movement) is calculated in a similar way: (speed*cos(velocityPitch)*cos(velocityHeading), speed*cos(velocityPitch)*sin(velocityHeading), speed*sin(velocityPitch)).
+
The velocity vector (direction and speed of movement) is calculated in a similar way: {{c|(speed*cos(velocityPitch)*cos(velocityHeading), speed*cos(velocityPitch)*sin(velocityHeading), speed*sin(velocityPitch))}}.
    
===CGameCtnGhost (03 092 000)===
 
===CGameCtnGhost (03 092 000)===
 
CGameCtnGhost is a subclass of CGameGhost. If you encounter an unknown chunk ID while reading a CGameCtnGhost instance, delegate it to CGameGhost.
 
CGameCtnGhost is a subclass of CGameGhost. If you encounter an unknown chunk ID while reading a CGameCtnGhost instance, delegate it to CGameGhost.
 +
 +
'''03092000''' (skippable)
 +
uint32
 +
meta playerModel
 +
vec3
 +
 +
uint32 numSkinRef
 +
fileref skinRef[numSkinRef]
 +
 +
uint32
 +
string ghostNickname
 +
string ghostAvatarFile
 +
uint32
    
'''03092005''' (skippable)
 
'''03092005''' (skippable)
Line 589: Line 916:     
'''0309200B''' (skippable)
 
'''0309200B''' (skippable)
  uint32 num
+
  uint32 numCheckpoints
  uint64[num]
+
  for each checkpoint:
 +
    uint32 time
 +
    uint32 stuntsScore (usually 0 in TM2)
    
'''0309200C'''
 
'''0309200C'''
Line 628: Line 957:     
'''03092019'''
 
'''03092019'''
  uint32 eventsDuration
+
  uint32 eventsDuration (if 0 then stop reading this chunk)
 
  uint32 ignored
 
  uint32 ignored
 
  uint32 numControlNames
 
  uint32 numControlNames
Line 647: Line 976:  
  uint32
 
  uint32
   −
===CGameCtnCollector (0301A000)===
+
===CGameCtnCollector (03 01A 000)===
 
Base class for CGameCtnBlockInfo, CGameCtnMacroBlockInfo, CGameCtnObjectInfo and CGameCtnDecoration.
 
Base class for CGameCtnBlockInfo, CGameCtnMacroBlockInfo, CGameCtnObjectInfo and CGameCtnDecoration.
   −
Deprecated. Moved to the new GameData engine (2E) as class CGameCtnCollector (2E001000).
+
Mapped to the new GameData engine (2E) as class CGameCtnCollector (2E001000).
    
'''0301A003''' ''"Desc"'' (header)
 
'''0301A003''' ''"Desc"'' (header)
 
  meta (name, collection, author)
 
  meta (name, collection, author)
 
  lookbackstring version
 
  lookbackstring version
  string pagePath (slash-separated folder path where the block appears in the editor)
+
  string pageName (slash-separated folder path where the block appears in the editor)
  if version = 5
+
  if version == 5:
 
     lookbackstring
 
     lookbackstring
  if version >= 4
+
  if version >= 4:
 
     lookbackstring
 
     lookbackstring
  if version >= 3
+
  if version >= 3:
     uint32 flags
+
     struct SCollectorDescFlags
     uint16 index
+
    {
  if version >= 7
+
        uint32 __unused2__ : 1;
 +
        uint32 IsInternal  : 1;
 +
        uint32 IsAdvanced  : 1;
 +
        uint32 IconDesc    : 5;  // 0 = Unknown, 1 = NoIcon, 2 = 64x64, 3 = 128x128
 +
        uint32 __unused__  : 24;
 +
    };
 +
     uint16 catalogPosition (order of the blocks within pageName)
 +
  if version >= 7:
 
     string name
 
     string name
 +
if version >= 8:
 +
    byte prodState (0: Aborted, 1: GameBox, 2: DevBuild, 3: Release)
    
'''0301A004''' ''"Icon"'' (header)
 
'''0301A004''' ''"Icon"'' (header)
 
  uint16 iconWidth
 
  uint16 iconWidth
 
  uint16 iconHeight
 
  uint16 iconHeight
  byte iconData[4*iconWidth*iconHeight]   // one RGBA uint32 per pixel
+
  if (int16)iconWidth >= 0 && (int16)iconHeight >= 0:
 +
    byte iconData[4*iconWidth*iconHeight] // one RGBA uint32 per pixel
 +
else:
 +
    uint16 version
 +
    if version >= 1:
 +
        uint32 size
 +
        byte iconData[size] // WebP image
    
'''0301A006''' (header)
 
'''0301A006''' (header)
Line 681: Line 1,025:  
  uint32
 
  uint32
 
  uint32
 
  uint32
 +
 +
'''0301A008'''
 +
byte
 +
string skinFile
    
'''0301A009'''
 
'''0301A009'''
Line 705: Line 1,053:  
  string defaultSkinName
 
  string defaultSkinName
   −
===CGameCtnObjectInfo (0301C000)===
+
===CGameCtnObjectInfo (03 01C 000)===
Deprecated. Moved to the new GameData engine (2E) as class CGameItemModel (2E002000).
+
Mapped to the new GameData engine (2E) as class CGameItemModel (2E002000).
    
'''0301C000''' (header)
 
'''0301C000''' (header)
  uint32 objectInfoType (0: Undefined, 1: Ornament, 2: PickUp, 3: Character, 4: Vehicle)
+
  uint32 itemType (0: Undefined, 1: Ornament (formerly: StaticObject), 2: PickUp (formerly: DynaObject), 3: Character, 4: Vehicle, 5: Spot, 6: Cannon, 7: Group, 8: Decal, 9: Turret, 10: Wagon, 11: Block, 12: EntitySpawner
''Note:'' In class CGameItemModel the enumerators are: 0: Undefined, 1: StaticObject, 2: DynaObject, 3: Character, 4: Vehicle, 5: Spot, 6: Cannon
      
'''0301C001''' (header)
 
'''0301C001''' (header)
Line 741: Line 1,088:     
'''0301C012'''
 
'''0301C012'''
  vec3D groundPoint
+
  vec3 groundPoint
 
  float painterGroundMargin
 
  float painterGroundMargin
 
  float orbitalCenterHeightFromGround
 
  float orbitalCenterHeightFromGround
Line 748: Line 1,095:     
'''301C013'''
 
'''301C013'''
  nodref audioEnvironmentInCar (CPlugAudioEnvironment; used for cars)
+
  noderef audioEnvironmentInCar (CPlugAudioEnvironment; used for cars)
    
'''301C014'''
 
'''301C014'''
Line 769: Line 1,116:  
'''0301C019'''
 
'''0301C019'''
 
  int version
 
  int version
  nodref phyModel                 // CPlugSurface
+
  noderef phyModel               // CPlugSurface
  nodref visModel                 // CPlugSurface
+
  noderef visModel               // CPlugSurface
 
  if version >= 1:
 
  if version >= 1:
     nodref visModelStatic       // CPlugSolid2Model
+
     noderef visModelStatic     // CPlugSolid2Model
   −
===CGameCtnDecoration (03038000)===
+
===CGameCtnDecoration (03 038 000)===
 
'''03038000''' ''"MoodRemaping"''
 
'''03038000''' ''"MoodRemaping"''
 
  byte version
 
  byte version
Line 784: Line 1,131:  
  uint32 unknown
 
  uint32 unknown
   −
===CGameCtnCollection (03033000)===
+
===CGameCtnCollection (03 033 000)===
 
'''03033001''' ''"Desc"''
 
'''03033001''' ''"Desc"''
 
  byte version
 
  byte version
  lookbackstring environment
+
  lookbackstring collection
  bool
+
  bool needUnlock
 
  if version >= 1:
 
  if version >= 1:
 
     string iconEnv
 
     string iconEnv
 
     string iconCollection
 
     string iconCollection
 
     if version >= 2:
 
     if version >= 2:
         int32
+
         int32 sortIndex
 
         if version >= 3:
 
         if version >= 3:
             lookbackstring terrain
+
             lookbackstring defaultZone
 
             if version >= 4:
 
             if version >= 4:
 
                 meta (vehicle, collection, author)
 
                 meta (vehicle, collection, author)
 
                 if version >= 5:
 
                 if version >= 5:
                     string
+
                     string mapFid
                     float
+
                     vec2
                     float
+
                     vec2
                    float
+
                     if version == 5:
                    float
+
                         vec2 mapCoordElem
                     if version <= 5:
+
                     if version == 6 || version == 7:
                         float
+
                         vec2 mapCoordElem
                        float
+
                         vec2 mapCoordIcon
                     if version <= 7:
  −
                         float
  −
                         float
   
                     if version >= 7:
 
                     if version >= 7:
 
                         string loadscreen
 
                         string loadscreen
 
                         if version >= 8:
 
                         if version >= 8:
                             float
+
                             vec2 mapCoordElem
                             float
+
                             vec2 mapCoordIcon
                             float
+
                             vec2 mapCoordDesc
                            float
+
                             string longDesc
                            float
  −
                            float
  −
                             string
   
                             if version >= 9:
 
                             if version >= 9:
                                 string name
+
                                 string displayName
 
                                 if version >= 10:
 
                                 if version >= 10:
                                     bool
+
                                     bool isEditable
    
'''03033002''' ''"CollectorFolders"''
 
'''03033002''' ''"CollectorFolders"''
 
  byte version
 
  byte version
  string dirName
+
  string folderBlockInfo
  string dirName
+
  string folderItem
  string dirName
+
  string folderDecoration
 
  if version == 1 || version == 2:
 
  if version == 1 || version == 2:
     string dirName
+
     string folder
 
  if version >= 2:
 
  if version >= 2:
     string dirName
+
     string folderCardEventInfo
 
  if version >= 3:
 
  if version >= 3:
     string dirName
+
     string folderMacroBlockInfo
 
  if version >= 4:
 
  if version >= 4:
     string dirName
+
     string folderMacroDecals
    
'''03033003''' ''"MenuIconsFolders"''
 
'''03033003''' ''"MenuIconsFolders"''
 
  byte version
 
  byte version
  string dirName
+
  string folderMenusIcons
 +
 
 +
===CGameSkin (03 031 000)===
 +
Moved to engine Plug (09) as class CPlugGameSkin (090F4000).
   −
===CGameSkin (03031000)===
   
'''03031000''' ''"Skin"''
 
'''03031000''' ''"Skin"''
 
  byte version
 
  byte version
Line 856: Line 1,199:  
     string file
 
     string file
 
     if version >= 2:
 
     if version >= 2:
         bool mipMap
+
         bool needMipMap
 
  if version >= 4:
 
  if version >= 4:
 
     string dirNameAlt
 
     string dirNameAlt
 
  if version >= 5:
 
  if version >= 5:
     bool unknown
+
     bool useDefaultSkin
   −
===CGamePlayerProfile (0308C000)===
+
===CGamePlayerProfile (03 08C 000)===
 
'''0308C000''' ''"NetPlayerProfile"''
 
'''0308C000''' ''"NetPlayerProfile"''
  string login
+
  string onlineLogin
 
  string onlineSupportKey
 
  string onlineSupportKey
   −
===CMwNod (01001000)===
+
===CGameCtnMediaClipGroup (03 07A 000)===
 +
'''0307A003'''
 +
uint32 ignored (0xA)
 +
uint32 numClips
 +
for each clip:
 +
    noderef clip
 +
uint32 numClips
 +
for each clip:
 +
    vec3 referenceFramePosition (NaN if none)
 +
    uint32 referenceFrameRotation
 +
    uint32 triggerCondition (0: None, 1: Time < arg, 2: Time > arg, 3: Already triggered, 4: Speed < arg, 5: Speed > arg, 6: Not already triggered)
 +
    float triggerArgument
 +
    uint32 numTriggers
 +
    for each trigger:
 +
        vec3 position
 +
 
 +
===CGameCtnMediaClip (03 079 000)===
 +
'''03079002'''
 +
uint32
 +
uint32 numTracks
 +
for each track:
 +
    noderef mediaTrack
 +
string clipName
 +
uint32
 +
 
 +
'''03079003'''
 +
uint32
 +
uint32 numTracks
 +
for each track:
 +
    noderef mediaTrack
 +
string clipName
 +
 
 +
'''03079004''' (all fields are ignored)
 +
uint32
 +
 
 +
'''03079005'''
 +
uint32 ignored (0xA)
 +
uint32 numTracks
 +
for each track:
 +
    noderef mediaTrack
 +
string clipName
 +
 
 +
'''03079007'''
 +
uint32 localPlayerClipEntIndex
 +
 
 +
'''0307900A'''
 +
bool stopWhenLeave
 +
 
 +
'''0307900D'''
 +
uint32
 +
uint32 version
 +
uint32 numTracks
 +
for each track:
 +
    noderef mediaTrack
 +
string clipName
 +
bool stopWhenLeave
 +
bool
 +
bool stopWhenRespawn
 +
string
 +
float
 +
uint32 localPlayerClipEntIndex
 +
 
 +
===CGameCtnMediaTrack (03 078 000)===
 +
'''03078001'''
 +
string trackName
 +
uint32 ignored (0xA)
 +
uint32 numTracks
 +
for each track:
 +
    noderef mediaBlock
 +
uint32 unknown
 +
 
 +
'''03078004'''
 +
bool keepPlaying
 +
uint32 ignored (0)
 +
 
 +
===CControlEffectSimi (07 010 000)===
 +
'''07010003'''
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
    vec2 position
 +
    float rotation (in rad)
 +
    float scaleX
 +
    float scaleY
 +
    float opacity
 +
    float depth
 +
bool centered
 +
 
 +
'''07010004'''
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
    vec2 position
 +
    float rotation (in rad)
 +
    float scaleX
 +
    float scaleY
 +
    float opacity
 +
    float depth
 +
    float
 +
    float isContinousEffect
 +
    float
 +
    float
 +
bool centered
 +
uint32 colorBlendMode
 +
bool isContinousEffect
 +
 
 +
'''07010005'''
 +
ReadChunk(0x07010004)
 +
bool isInterpolated
 +
 
 +
===CGameCtnMediaBlock===
 +
 
 +
====CGameCtnMediaBlockCameraPath (03 0A1 000)====
 +
'''030A1002'''
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
    vec3 cameraPosition
 +
    float pitch (rad)
 +
    float yaw  (rad)
 +
    float roll  (rad)
 +
    float FOV
 +
    bool anchorRot
 +
    uint32 indexTargetPlayer (maxint: None, 0: Local player)
 +
    bool anchorVis
 +
    uint32 indexAnchorPlayer (maxint: None, 0: Local player)
 +
    vec3 targetPosition
 +
    float weight
 +
    float
 +
    float
 +
    float
 +
    float
 +
 
 +
====CGameCtnMediaBlockCameraCustom (03 0A2 000)====
 +
'''030A2005'''
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
    uint32 interpolation (0: None, 1: Hermit, 2: Linear, 3: FixedTangent)
 +
    uint64 unused (0)
 +
    vec3 cameraPosition
 +
    float pitch (rad)
 +
    float yaw  (rad)
 +
    float roll  (rad)
 +
    float FOV
 +
    bool anchorRot
 +
    uint32 indexTargetPlayer (maxint: None, 0: Local player)
 +
    bool anchorVis
 +
    uint32 indexAnchorPlayer (maxint: None, 0: Local player)
 +
    vec3 targetPosition
 +
    float leftTangentX
 +
    float leftTangentY
 +
    float leftTangentZ
 +
    float rightTangentX
 +
    float rightTangentY
 +
    float rightTangentZ
 +
 
 +
====CGameCtnMediaBlockCameraEffectShake (03 0A4 000)====
 +
'''030A4000'''
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
    float intensity
 +
    float speed
 +
 
 +
====CGameCtnMediaBlockImage (03 0A5 000)====
 +
'''030A5000'''
 +
noderef CControlEffectSimi
 +
fileref image
 +
 
 +
====CGameCtnMediaBlockMusicEffect (03 0A6 000)====
 +
'''030A6001'''
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
    float musicVolume
 +
    float soundVolume
 +
 
 +
====CGameCtnMediaBlockSound (03 0A7 000)====
 +
'''030A7001'''
 +
fileref sound
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
    float volume
 +
    float pan
 +
 
 +
'''030A7002'''
 +
uint32 playCount
 +
bool isLooping
 +
 
 +
'''030A7003'''
 +
uint32 version
 +
uint32 playCount
 +
bool isLooping
 +
bool isMusic
 +
if version >= 1:
 +
    bool stopWithClip
 +
    if version >= 2:
 +
        bool audioToSpeech
 +
        int audioToSpeechTarget
 +
 
 +
'''030A7004'''
 +
fileref sound
 +
uint32 ignored (1)
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
    float volume
 +
    float pan (unused)
 +
    vec3 soundTransmitorPosition
 +
 
 +
====CGameCtnMediaBlockText (03 0A8 000)====
 +
'''030A8001'''
 +
string text
 +
noderef CControlEffectSimi
 +
 
 +
'''030A8002'''
 +
color textColor (with in-game color selector format)
 +
 
 +
====CGameCtnMediaBlockTrails (03 0A9 000)====
 +
'''030A9000'''
 +
float timeClipStart
 +
float timeClipEnd
 +
 
 +
====CGameCtnMediaBlockTransitionFade (03 0AB 000)====
 +
'''030AB000'''
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
    float opacity
 +
color transitionColor (with in-game color selector format)
 +
float ignored (1.0)
 +
 
 +
====CGameCtnMediaBlockFxColors (03 080 000)====
 +
'''03080003'''
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
    float intensity
 +
    float blendZ          (far)
 +
    float distance        (near)
 +
    float distance        (far)
 +
    additionnalParameters (near)
 +
    additionnalParameters (far)
 +
 
 +
additionnalParameters format:
 +
    float inverse
 +
    float hue
 +
    float saturation
 +
    float brightness
 +
    float contrast
 +
    color
 +
    float ignored  (1.0)
 +
    float ignored  (1.0)
 +
    float ignored  (1.0)
 +
    float ignored  (0.0)
 +
 
 +
====CGameCtnMediaBlockFxBlurDepth (03 081 000)====
 +
'''03081001'''
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
    float lensSize
 +
    bool forceFocus
 +
    float focusZ
 +
 
 +
====CGameCtnMediaBlockFxBlurMotion (03 082 000)====
 +
'''03082000'''
 +
float timeClipStart
 +
float timeClipEnd
 +
 
 +
====CGameCtnMediaBlockFxBloom (03 083 000)====
 +
'''03083001'''
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
    float intensity
 +
    float sensitivity
 +
 
 +
====CGameControlCameraFree (03 084 000)====
 +
'''03084003'''
 +
float timeClipStart
 +
float timeClipEnd
 +
lookbackstring cameraView
 +
uint32 indexTargetPlayer (0: Local player)
 +
 
 +
====CGameCtnMediaBlockTime (03 085 000)====
 +
'''03085000'''
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
    float timeValue
 +
    float tangent
 +
 
 +
====CGameCtnMediaBlock3dStereo (03 024 000)====
 +
'''03024000'''
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
    float separation
 +
    float screenDist
 +
 
 +
====CGameCtnMediaBlockTriangles (03 029 000)====
 +
'''03029001'''
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
uint32 numKeys
 +
uint32 numPoints
 +
for each key:
 +
    for each point:
 +
        vec3 pointPosition
 +
uint32 numPoints
 +
for each point: 
 +
    color pointColor (with in-game color selector format)
 +
    float opacity
 +
uint32 numTriangles
 +
for each triangle:  (index of the 3 vertices forming the triangle)
 +
    uint32 vertex1
 +
    uint32 vertex2
 +
    uint32 vertex3
 +
uint32 ignored (1)
 +
uint32 ignored (0)
 +
uint32 ignored (0)
 +
float  ignored (1.0)
 +
uint32 ignored (0)
 +
uint64 ignored (0)
 +
 
 +
====CGameCtnMediaBlockGhost (03 0E5 000)====
 +
'''030E5001'''
 +
float timeClipStart
 +
float timeClipEnd
 +
noderef ghostModel (CGameCtnGhost)
 +
float startOffset
 +
 
 +
'''030E5002'''
 +
uint32 version
 +
if version < 3:
 +
    float timeClipStart
 +
    float timeClipEnd
 +
if version >= 3:
 +
    uint32 numKeys
 +
    for each key:
 +
        float timeStamp
 +
        float
 +
noderef ghostModel (CGameCtnGhost)
 +
float startOffset
 +
bool noDamage
 +
bool forceLight
 +
bool forceHue
 +
 
 +
===CMwNod (01 001 000)===
 
'''01001000''' ''"FolderDep"''
 
'''01001000''' ''"FolderDep"''
 
  uint32 number
 
  uint32 number
Line 873: Line 1,568:  
     string dirName
 
     string dirName
   −
== Historical information ==
+
== References to the actual functions ==
While the above description of *.Gbx files is far more complete and precise than before, it is also entirely different from &ndash; and more abstract than &ndash; the original description, which formed the basis for several of the tools below.  That historical description can still be viewed at this [http://en.tm-wiki.org/index.php?title=GBX&oldid=5300 revision link].
+
<references />
    
== Applications and Libraries that can inspect/modify the file format ==
 
== Applications and Libraries that can inspect/modify the file format ==
    +
* [[GbxDump]] - a Windows tool to dump and analyze the header of all kinds of .Gbx files.
 
* [http://www.xaseco.org/tools.php GBX Data Fetcher] - a PHP module with classes to extract useful data from .Challenge|Map.Gbx files (including the thumbnail image), .Replay.Gbx files and .Pack.Gbx|.pak files, as well as parse their XML blocks.
 
* [http://www.xaseco.org/tools.php GBX Data Fetcher] - a PHP module with classes to extract useful data from .Challenge|Map.Gbx files (including the thumbnail image), .Replay.Gbx files and .Pack.Gbx|.pak files, as well as parse their XML blocks.
 
* [http://www.xaseco.org/tools.php Extract GBX data] - a PHP script to format and print data from all file types supported by the GBX Data Fetcher module.
 
* [http://www.xaseco.org/tools.php Extract GBX data] - a PHP script to format and print data from all file types supported by the GBX Data Fetcher module.
* [http://www.xaseco.org/tools.php Tally GBX versions] - a PHP script to tally some version data from all .Challenge|Map.Gbx files (including sample challenges in all known versions).
+
* [http://www.xaseco.org/tools.php Tally GBX versions] - a PHP script to tally some version data from all .Challenge|Map.Gbx files (includes sample challenges in all known versions).
* [http://tossha.ru/trackstudio/ TrackStudio] - a Windows TrackMania Forever track editor with 3D interface.
+
* [https://github.com/BigBang1112/gbx-net GBX.NET] - a C#/.NET parser for .Gbx files.
* [http://www.mania-creative.com/talk/showthread.php?threadid=644 Blockmix tools] - Challenge editing tools (Recompressor, ChallengeEdit, GBX-Master, CELightRotate, TmfBlockMixEdition).
+
* [https://github.com/donadigo/pygbx pygbx] - a Python library to parse .Gbx files.
* [http://www.mania-creative.com/talk/showthread.php?threadid=2379 TMPakTool] - Open and edit .pak files.
+
* [https://github.com/ThaumicTom/gbx.js gbx.js] - a slim, fast and easy to set up Gamebox (GBX) parser written in vanilla JavaScript.
* [http://www.mania-creative.com/talk/showthread.php?threadid=2421 TMUnlimiter] - Patches the in-game track editor to remove the block placement restrictions.
+
* [https://github.com/stefan-baumann/ManiaPlanetSharp ManiaPlanetSharp] - a .NET library, written in C#, which provides easy-to-use, object-oriented ways to access data and services related to ManiaPlanet.
* [http://forum.maniaplanet.com/viewtopic.php?t=19432 GBXedit] - Command-line based blockmix editor for TM² Stadium maps.
  −
* [http://forum.maniaplanet.com/viewtopic.php?t=19890 MapEdit] - GUI-based blockmix editor for all ManiaPlanet maps.
  −
* [[GbxDump]] - a Windows tool to dump and analyze the header of all kinds of .Gbx files.
  −
* [http://www.wolfgang-rolke.de/gbxdump/gbxconv.zip ReplayToChallenge] - a Windows tool to extract a Challenge from a .Replay.Gbx file (includes source code).
  −
* [[Easy TM]]
   
* [http://micolous.id.au/pages/disasm.html Trackmania Disassembler] - includes a library allowing you to write your own applications that can read the format.
 
* [http://micolous.id.au/pages/disasm.html Trackmania Disassembler] - includes a library allowing you to write your own applications that can read the format.
 +
* {{ArchiveOrg|http://tossha.ru/trackstudio/|TrackStudio|https://web.archive.org/web/20160319194133/http://tossha.ru/trackstudio/}} - a Windows TrackMania Forever track editor with 3D interface.
 +
* {{ArchiveOrg|http://forum.mania-creative.com/thread-644.html|Blockmix tools|https://web.archive.org/web/20130214000026/http://forum.mania-creative.com/thread-644.html}} - Challenge editing tools (Recompressor, ChallengeEdit, GBX-Master, CELightRotate, TmfBlockMixEdition).
 +
* {{ArchiveOrg|http://forum.mania-creative.com/thread-2379.html|TMPakTool|https://web.archive.org/web/20121007000654/http://forum.mania-creative.com/thread-2379.html}} - an open source tool which can open and edit .pak files in an Explorer-like interface. Comes with a C# library which you can use in your own applications to work with .pak files. [http://www.mediafire.com/file/y4klvl2op6cpd4p/TMPakTool-v0.2.zip Download] & [http://www.mediafire.com/file/lq3j99k4tk6uav9/TMPakTool-v0.2+src.zip Source code]
 +
* {{ArchiveOrg|http://forum.mania-creative.com/thread-2421.html|TMUnlimiter|https://web.archive.org/web/20120615190003/http://forum.mania-creative.com/thread-2421.html}} - Patches the in-game track editor to remove the block placement restrictions. [http://www.mediafire.com/file/762s27a2gdihsa2/TMUnlimiter-v0.4.2+src.zip Source code]
 +
* {{mpforum|19432|GBXedit}} - Command-line based blockmix editor for TM² Stadium maps.
 +
* {{mpforum|19890|MapEdit}} - GUI-based blockmix editor for all ManiaPlanet maps.
 +
* [http://www.wolfgang-rolke.de/gbxdump/gbxconv.zip ReplayToChallenge download] - a Windows tool to extract a Challenge from a .Replay.Gbx file (includes source code).
 +
* [http://www.wolfgang-rolke.de/gbxdump/gbxdecomp.zip GbxDecompress download] - a Windows tool that decompresses or compresses the file body of a given .Gbx file (includes source code).
 +
* [http://www.wolfgang-rolke.de/gbxdump/gbxiteminfo.zip EmbeddedItems download] - a Windows tool that indicates all embedded items of a given .Map.Gbx file (includes source code).
 +
* [http://www.wolfgang-rolke.de/gbxdump/gbxlightmap.zip GbxLightMap download] - a Windows tool to extract the lightmaps from a given .Map.Gbx file (includes source code).
 +
* [http://www.wolfgang-rolke.de/gbxdump/gbxmetadata.zip GbxMetadata download] - a Windows tool that indicates the persistent attributes of a given .Map.Gbx file (includes source code).
 +
* [[File:Krzychor-campaign-maker.zip]] - a Windows tool that allows to create custom campaigns for TMNF/TMUF. Sources not included.
 +
 +
[[Category:File formats]]
33

edits

Navigation menu