Format changed as of 1.14, old format (pre-1.13) is Legacy. The older format is still being used in some STU file types.
"void*" and any pointer (*) is an uint, not long.
uint instance_count; STUInstanceInfo* instance_list; // Size is instance_count uint array_reference_count; STUArrayRefInfo* array_reference_list; // Size is array_reference_count uint instance_field_list_count; STUFieldInfo* instance_field_list; // Size is instance_field_list_count uint array_buffer_size; char* array_buffer; // Size is array_buffer_size uint data_offset; // STU instances start at this offset.
This structure describes each STU in the file.
uint checksum; // CRC32 IEEE / CRC32b of the STU instance name uint field; // CRC32b of the parent field. Ignore if 0. int index; // Index of the parent instance. Ignore if -1. instances[index][field] = this. uint size; // Absolute size of the instance.
This structure describes if any array needs STU pre-processing.
uint checksum; // CRC32 IEEE / CRC32b of the STU instance name uint size; // Absolute size of each entry(?) or padding bytes.
This structure describes a field array, there can be more than 1 field array per STU.
uint count; // Number of fields. STUField* fields; // Size is count
This structure defines a field. The order is important.
uint checksum; // CRC32 IEEE / CRC32b of the STU field name uint size; // Absolute size of each field.
Zero size fields are nested structures.
Parsing STU Instances
Each instance is prefixed with an int. This value is the field info index. Use this field array to get information about a field.
STUs do not have any offsets stored that point to themselves.
Nested structures are similar to STU instances, these will always have a field size of **zero**, indicating a dynamically sizing structure.
In this case you should read a single unsigned integer.
uint field_size; // size of nested structure
This is the buffer size. Read field_size bytes as a buffer then parse it as a new instance. In the case of arrayed nested structures, you must shrink the buffer once reading is done and read a new instance. Repeat this until the buffer is length zero.
This structure describes the array, it's prefixed to each array.
uint count; // No. of entries int unknown; // Index of reference STU to process the value(s)? void* data; // Size is count. Each entry size is determined by the STU parsing the array. uint unknown; // Zero
GUIDs can be mangled, in this case you need to run a CRC64-J (jones, polynomial 0x1AD93D23594C935A9) on the STU header (first 36 bytes), this will be the header checksum.
Then shift the field's hash to repeat itself once
ulong field_hash = hash | (hash << 32);
Then XOR the mangled GUID with the header checksum and the double field hash.
ulong demangled_guid = guid ^ header_hash ^ field_hash;
Then swap byte 0 with byte 3, byte 7 with byte 1, byte 2 with byte 6, byte 4 with byte 5.
You may have to XOR the final value with 0xFFFFFFFFFFFFFFFF.
Detecting mangled GUID fields
Has to do with the field CRC hash, TODO.
Chunked model files can contain STU instances. This is defined in the MSTU chunk.
The format contained within the MSTU is identical to a normal STU however, it's prefixed with the following:
char* buffer; // long, Size is size. Points to the STU instance. ulong size;