Skip to content

File format

Pyogenics edited this page Oct 30, 2024 · 3 revisions

Each model used in WOTB is made up of two files: SCG and SC2; SCG files only contain geometry like index buffers and model vertices (coordinates, UVs etc...) whilst SC2 files contain scene and hierarchy data that ties it all together. Both formats are based upon a custom data structures called "Keyed archives" which encodes a JSON-like structure with key/value pairs but in binary form.

Keyed archive

Keyed archives are JSON-like binary structures that can hold key/value pairs. There are 2 version with 4 total variants:

Version Description
1.0 Oldest version, used in SCG and old SC2 versions
2.0 Keys are all encoded using the fastname system
2.1 This is only used for KAs that are children of version 2.0, relies on the fastname table of the root KA
2.255 This is always empty

Format

struct KA
{
    char signature[2]; // "KA"
    short version;
    // version specific data
    KA1Body body;       // Only if version == 0x0001
    KA2Body body;       // Only if version == 0x0002
    KA2_1Body body;     // Only if version == 0x0102
    KA2_255Body body;   // Only if version == 0xff02
}; 

Datatypes

KA supports a wide range of data types:

enum KADatatype
{
  NONE = 0,
  BOOLEAN = 1,
  INT32 = 2,
  FLOAT = 3,
  STRING = 4,
  WIDE_STRING = 5,
  BYTE_ARRAY = 6,
  UINT32 = 7,
  KEYED_ARCHIVE = 8,
  INT64 = 9,
  UINT64 = 10,
  VECTOR2 = 11,
  VECTOR3 = 12,
  VECTOR4 = 13,
  MATRIX2 = 14,
  MATRIX3 = 15,
  MATRIX4 = 16,
  COLOR = 17,
  FASTNAME = 18,
  AABBOX3 = 19,
  FILEPATH = 20,
  FLOAT64 = 21,
  INT8 = 22,
  UINT8 = 23,
  INT16 = 24,
  UINT16 = 25,
  ARRAY = 27,
  TRANSFORM = 29,
};

version 1.0, KA1Body

Version 1 KA data, this is the simplest version.

struct KA1Body
{
    int nodeCount;
    struct {
        char keyDatatype;
        void* key;
        char valueDatatype;
        void* value;
    } children[nodeCount]; // this encodes {key: value}
};

version 2.0, KA2Body

Version 2 KA data, uses the fastname system for key names.

struct KA2Body
{
    int fastnameCount;
    struct {
        short stringLength;
        char string[stringLength];
    } fastnames[fastnameCount];
    int fastnameIDs[fastnameCount];
    int nodeCount;
    struct {
        int keyID; // Corresponds to a value in fastnameIDs, the index of the ID in fastnameIDs is the index of the string inside fastnames
        char valueDatatype;
        void* value;
    } children[nodeCount]; // this encode {key: value}
};

version 2.1, KA2_1Body

Version 2 KA data, this variant is always a child of a version 2.0 or 2.1 node.

struct KA2_1Body
{
    int nodeCount;
    struct {
        int keyID; // Corresponds to a value in root node's fastnameIDs, the index of the ID in fastnameIDs is the index of the string inside fastnames
        char valueDatatype;
        void* value;
    } children[nodeCount]; // this encode {key: value}
};

Version 2.255, KA2_255Body

This variant is empty, contains no data.

SCG

Only stores geometry data.

Format

struct SCG
{
    char signature[4]; // "SCPG"
    int version; // 1, at time of writing
    int nodeCount;
    int nodeCountCopy; // Should be identical to nodeCount
    KA nodes[nodeCount]; // Keyed archives should be version 1
};

SC2

Stores scene data but can also store geometry data and is usually paired with a matching SCG file (unless the SC2 already contains its own geometry).

Format

struct SC2
{
    char signature[4]; // "SFV2"
    int version;
    int nodeCount;
    KA versionTags;
    int descriptorLength;
    char descriptorBytes[length];
    KA nodes[nodeCount]; // Should be version 2 KA
};