Changes

Jump to navigation Jump to search
6,264 bytes added ,  15:45, 4 November 2022
→‎Reading the body: Added Encapsulation
Line 172: Line 172:     
''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.
 
''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 ==
Line 381: Line 402:  
  uint32 version
 
  uint32 version
 
  if version >= 5:
 
  if version >= 5:
    uint32 frames  // If version < 5 then frames = 1
+
    uint32 frames  // If version < 5 then frames = 1
 
  if version >= 2:
 
  if version >= 2:
    for each frame:
+
    for each frame:
      uint32 size
+
        uint32 size
      byte image[size]  // Image is JPEG/JFIF or WEBP/RIFF file format
+
        byte image[size]  // Image is JPEG/JFIF or WEBP/RIFF file format
      if version >= 3:
+
        if version >= 3:
          uint32 size
+
            uint32 size
          byte image[size]
+
            byte image[size]
      if version >= 6:
+
        if version >= 6:
          uint32 size
+
            uint32 size
          byte image[size]
+
            byte image[size]
    if size != 0:
+
    if size != 0:
      uint32 uncompressedSize
+
        uint32 uncompressedSize
      uint32 compressedSize
+
        uint32 compressedSize
      byte compressedData[compressedSize] // ZLIB compressed lightmap cache node
+
        byte compressedData[compressedSize] // ZLIB compressed lightmap cache node
    
'''03043040''' (skippable) ''"items"''
 
'''03043040''' (skippable) ''"items"''
   −
''Note:'' This chunk resets the lookback string state.
+
''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 version
  if version != 0:
+
  uint32
  uint32
+
uint32 size
  uint32 size
+
uint32 (10)
  uint32 (10)
+
uint32 numItems
  uint32 numItems
+
for each item:
  for each item:
+
     node item (CGameCtnAnchoredObject, direct node)
     noderef item (CGameCtnAnchoredObject)
+
if version >= 1 && version != 5:
  uint32
+
    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)
 
'''03043044''' (skippable)
Line 417: Line 466:  
  uint32 version
 
  uint32 version
 
  if version >= 2:
 
  if version >= 2:
  uint32 count (number of metadata records)
+
    uint32 count (number of metadata records)
  for each count:
+
    for each count:
    string varName
+
        string varName
    uint32 varType
+
        uint32 varType
    switch 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:
 
             case EType_Boolean:
              bool
+
                bool
 
             case EType_Integer:
 
             case EType_Integer:
              int32
+
                int32
 
             case EType_Real:
 
             case EType_Real:
              float
+
                float
 
             case EType_Text:
 
             case EType_Text:
              string
+
                string
          switch typeValue:
  −
            case EType_Boolean:
  −
              bool
  −
            case EType_Integer:
  −
              int32
  −
            case EType_Real:
  −
              float
  −
            case EType_Text:
  −
              string
   
             case EType_Int2:
 
             case EType_Int2:
              int32
+
                int32
              int32
+
                int32
 
             case EType_Int3:
 
             case EType_Int3:
              int32
+
                int32
              int32
+
                int32
              int32
+
                int32
 
             case EType_Vec2:
 
             case EType_Vec2:
              float
+
                float
              float
+
                float
 
             case EType_Vec3:
 
             case EType_Vec3:
              float
+
                float
              float
+
                float
              float
+
                float
 
             case EType_Array:
 
             case EType_Array:
              recursively read multidimensional arrays
+
                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:
 
The variable type is to be interpreted as follows:
 
  enum eScriptType
 
  enum eScriptType
 
  {
 
  {
  EType_Void = 0,
+
    EType_Void = 0,
  EType_Boolean,
+
    EType_Boolean,
  EType_Integer,
+
    EType_Integer,
  EType_Real,
+
    EType_Real,
  EType_Class,
+
    EType_Class,
  EType_Text,
+
    EType_Text,
  EType_Enum,
+
    EType_Enum,
  EType_Array,
+
    EType_Array,
  EType_ParamArray,
+
    EType_ParamArray,
  EType_Vec2,
+
    EType_Vec2,
  EType_Vec3,
+
    EType_Vec3,
  EType_Int3,
+
    EType_Int3,
  EType_Iso4,
+
    EType_Iso4,
  EType_Ident,
+
    EType_Ident,
  EType_Int2,
+
    EType_Int2,
  EType_Struct
+
    EType_Struct
 
  };
 
  };
 
Maniaplanet 4.1 has changed the way script types and values are written. The code now does the following:
 
Maniaplanet 4.1 has changed the way script types and values are written. The code now does the following:
Line 519: Line 568:     
'''03043054''' (skippable)
 
'''03043054''' (skippable)
 +
 +
''Note:'' This chunk has its own lookback string state (is encapsulated with CSystemArchiveEncapsuledChunk).
 +
 
  uint32 version (1)
 
  uint32 version (1)
 
  uint32
 
  uint32
Line 729: Line 781:  
  vec3 absolutePositionInMap
 
  vec3 absolutePositionInMap
 
  CGameWaypointSpecialProperty waypointSpecialProperty (-1 if not a waypoint, otherwise direct node)
 
  CGameWaypointSpecialProperty waypointSpecialProperty (-1 if not a waypoint, otherwise direct node)
 +
if version < 5:
 +
    uint32
 
  if version >= 4:
 
  if version >= 4:
  uint16 flags
+
    uint16 flags
  if version >= 5:
+
    if version >= 5:
    vec3 pivotPosition
+
        vec3 pivotPosition
    if version >= 6:
+
        if version >= 6:
      float scale
+
            float scale
      if version >= 8: // TM 2020
+
            if version >= 7:
        vec3
+
                if (flags & 4) == 4:
        vec3
+
                    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 859: Line 916:     
'''0309200B''' (skippable)
 
'''0309200B''' (skippable)
  uint32 cpNum
+
  uint32 numCheckpoints
  uint64 cpTimeMs[cpNum]
+
  for each checkpoint:
 +
    uint32 time
 +
    uint32 stuntsScore (usually 0 in TM2)
    
'''0309200C'''
 
'''0309200C'''
Line 936: Line 995:  
         uint32 IsInternal  : 1;
 
         uint32 IsInternal  : 1;
 
         uint32 IsAdvanced  : 1;
 
         uint32 IsAdvanced  : 1;
         uint32 IconDesc    : 5;  // 0 = Unknown, 1 = NoIcon, 2 = BGRA_64x64, 3 = BGRA_128x128
+
         uint32 IconDesc    : 5;  // 0 = Unknown, 1 = NoIcon, 2 = 64x64, 3 = 128x128
 
         uint32 __unused__  : 24;
 
         uint32 __unused__  : 24;
 
     };
 
     };
Line 948: Line 1,007:  
  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 1,162: Line 1,227:     
===CGameCtnMediaClip (03 079 000)===
 
===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)
 
'''03079004''' (all fields are ignored)
 
  uint32
 
  uint32
Line 1,167: Line 1,247:  
'''03079005'''
 
'''03079005'''
 
  uint32 ignored (0xA)
 
  uint32 ignored (0xA)
  uint32 numTypes
+
  uint32 numTracks
  for each type:
+
  for each track:
 
     noderef mediaTrack
 
     noderef mediaTrack
 
  string clipName
 
  string clipName
   −
'''03079007''' (all fields are ignored)
+
'''03079007'''
 +
uint32 localPlayerClipEntIndex
 +
 
 +
'''0307900A'''
 +
bool stopWhenLeave
 +
 
 +
'''0307900D'''
 
  uint32
 
  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)===
 
===CGameCtnMediaTrack (03 078 000)===
Line 1,189: Line 1,286:     
===CControlEffectSimi (07 010 000)===
 
===CControlEffectSimi (07 010 000)===
'''07010005'''
+
'''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
 
  uint32 numKeys
 
  for each key:
 
  for each key:
Line 1,199: Line 1,308:  
     float opacity
 
     float opacity
 
     float depth
 
     float depth
     int128 ignored (0)
+
     float
  int128 ignored
+
    float isContinousEffect
 +
    float
 +
    float
 +
bool centered
 +
uint32 colorBlendMode
 +
bool isContinousEffect
 +
 
 +
'''07010005'''
 +
ReadChunk(0x07010004)
 +
  bool isInterpolated
    
===CGameCtnMediaBlock===
 
===CGameCtnMediaBlock===
Line 1,260: Line 1,378:  
'''030A5000'''
 
'''030A5000'''
 
  noderef CControlEffectSimi
 
  noderef CControlEffectSimi
  byte ignored (2)
+
  fileref image
string folderPath
  −
if folderPath is not emptyString:
  −
    string locatorLink
      
====CGameCtnMediaBlockMusicEffect (03 0A6 000)====
 
====CGameCtnMediaBlockMusicEffect (03 0A6 000)====
Line 1,274: Line 1,389:     
====CGameCtnMediaBlockSound (03 0A7 000)====
 
====CGameCtnMediaBlockSound (03 0A7 000)====
 +
'''030A7001'''
 +
fileref sound
 +
uint32 numKeys
 +
for each key:
 +
    float timeStamp
 +
    float volume
 +
    float pan
 +
 +
'''030A7002'''
 +
uint32 playCount
 +
bool isLooping
 +
 
'''030A7003'''
 
'''030A7003'''
  uint32 ignored (0)
+
  uint32 version
 
  uint32 playCount
 
  uint32 playCount
  bool loopMusic
+
  bool isLooping
  bool musicOn
+
  bool isMusic
 +
if version >= 1:
 +
    bool stopWithClip
 +
    if version >= 2:
 +
        bool audioToSpeech
 +
        int audioToSpeechTarget
   −
'''0307A004'''
+
'''030A7004'''
  byte ignored (2)
+
  fileref sound
string folderPath
  −
if folderPath is not emptyString:
  −
    string locatorLink
   
  uint32 ignored (1)
 
  uint32 ignored (1)
 
  uint32 numKeys
 
  uint32 numKeys
Line 1,290: Line 1,419:  
     float timeStamp
 
     float timeStamp
 
     float volume
 
     float volume
     float ignored (0.0)
+
     float pan (unused)
 
     vec3 soundTransmitorPosition
 
     vec3 soundTransmitorPosition
   Line 1,365: Line 1,494:  
  float timeClipStart
 
  float timeClipStart
 
  float timeClipEnd
 
  float timeClipEnd
  uint32 flag
+
  lookbackstring cameraView
if flag == 0x3:
  −
    uint32 flag (when exported to clip the flag is moved)
  −
if flag == 0x40000000:
  −
    string cameraView
   
  uint32 indexTargetPlayer (0: Local player)
 
  uint32 indexTargetPlayer (0: Local player)
   Line 1,418: Line 1,543:  
  float timeClipStart
 
  float timeClipStart
 
  float timeClipEnd
 
  float timeClipEnd
  noderef CGameCtnGhost
+
  noderef ghostModel (CGameCtnGhost)
  float ghostOffset
+
  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)===
 
===CMwNod (01 001 000)===
Line 1,436: Line 1,577:  
* [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 (includes 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).
 +
* [https://github.com/BigBang1112/gbx-net GBX.NET] - a C#/.NET parser for .Gbx files.
 +
* [https://github.com/donadigo/pygbx pygbx] - a Python library to parse .Gbx files.
 +
* [https://github.com/ThaumicTom/gbx.js gbx.js] - a slim, fast and easy to set up Gamebox (GBX) parser written in vanilla JavaScript.
 +
* [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://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://tossha.ru/trackstudio/|TrackStudio|https://web.archive.org/web/20160319194133/http://tossha.ru/trackstudio/}} - a Windows TrackMania Forever track editor with 3D interface.
33

edits

Navigation menu