diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9cf281b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +Repository/ diff --git a/dt_bundle.bt b/dt_bundle.bt new file mode 100644 index 0000000..7d01435 --- /dev/null +++ b/dt_bundle.bt @@ -0,0 +1,54 @@ +//------------------------------------------------ +//--- 010 Editor v12.0.1 Binary Template +// +// File: +// Authors: +// Version: +// Purpose: +// Category: +// File Mask: +// ID Bytes: +// History: +//------------------------------------------------ + +typedef struct { + uint64 extension ; + uint64 name ; + uint32 flags ; +} FileMeta; + +uint32 format ; +uint32 unknown_1 ; +Assert(unknown_1 == 3); + +uint32 num_entries; +uint64 properties[32] ; + +FileMeta file_meta[num_entries]; + +uint32 num_chunks; +uint32 chunk_sizes[num_chunks]; + +local int padding_size = 16 - (FTell() % 16); +if (padding_size < 16) { + byte padding[padding_size]; +} + +uint32 unpacked_size; +uint32 unknown_3; + +local int chunk_index; +for (chunk_index = 0; chunk_index < num_chunks; chunk_index++) { + struct Chunk { + uint32 size ; + + local int padding_size = 16 - (FTell() % 16); + + if (padding_size < 16) { + byte padding[padding_size]; + } + + byte data[chunk_sizes[chunk_index]] ; + }; + Chunk chunks; +} \ No newline at end of file diff --git a/dt_bundle_database.bt b/dt_bundle_database.bt new file mode 100644 index 0000000..fd3b786 --- /dev/null +++ b/dt_bundle_database.bt @@ -0,0 +1,84 @@ +//------------------------------------------------ +//--- 010 Editor v12.0.1 Binary Template +// +// File: dt_bundle_database.dt +// Authors: +// Version: +// Purpose: +// Category: Darktide +// File Mask: bundle_database.data +// ID Bytes: +// History: +//------------------------------------------------ + +uint32 format ; +uint32 num_entries; + +typedef struct { + uint32 version; + Assert(version == 0x4); + + uint32 len_name; + char name[len_name]; + + uint32 len_stream; + char stream[len_stream]; + + byte platform_specific; // boolean + + // byte buffer[20] ; + byte buffer[20]; + + local int is_0 = true; + local int i = 0; + + for (i = 0; i < 15; i++) { + if (buffer[i] != 0) { + is_0 = false; + } + } + + if (!is_0) { + Warning("Unknown 20-byte buffer is not 0"); + } + + uint64 file_time; // win32 FILETIME +} File; + +typedef struct { + uint64 hash ; + uint32 num_files; + + File files[num_files] ; +} Entry; + +Entry entries[num_entries] ; + +uint32 num_hashes; + +typedef struct { + uint64 bundle ; + uint64 resource_hash ; +} ResourceHash; + +ResourceHash hashes[num_hashes]; + +if (format <= 5) { + return; +} + +uint32 num_contents; + +typedef struct { + uint64 extension ; + uint64 name ; +} Filename; + +typedef struct { + uint64 hash ; + uint32 num_files; + + Filename files[num_files]; +} BundleContents; + +BundleContents contents[num_contents] ; \ No newline at end of file diff --git a/dt_bundle_decompressed.bt b/dt_bundle_decompressed.bt new file mode 100644 index 0000000..75765ea --- /dev/null +++ b/dt_bundle_decompressed.bt @@ -0,0 +1,85 @@ +//------------------------------------------------ +//--- 010 Editor v12.0.1 Binary Template +// +// File: dt_bundle_decompressed.bt +// Authors: Lucas Schwiderski +// Version: +// Purpose: +// Category: Darktide +// File Mask: +// ID Bytes: +// History: +//------------------------------------------------ + +typedef struct { + uint64 extension ; + uint64 name ; + uint32 flags ; +} FileMeta; + +typedef struct { + uint32 lang ; + byte is_data_file ; + uint32 size; + byte unknown_2; + // If > 0, data chunk will be followed by a string of that length, which is an auxiliary/extension file + // to the data in the data chunk. + // Example: `.wwise_stream` only contains 12 bytes of data in the bundle, which includes an offset and a length. + // The extra file then contains the actual data. + uint32 len_data_file_name; + + if (is_data_file == 1) { + if (size > 40) { + Warning("is_data_file == true, but size is too big for a simple file name: size = %d", size); + } + if (len_data_file_name > 0) { + Warning("is_data_file == true, but we also got len_data_file_name > 0"); + } + } + + if (unknown_2 != 1) { + Assert("Expected '1' for 'unknown_2', got '%x'", unknown_2); + } +} FileHeader; + +typedef struct { + uint64 extension ; + uint64 name ; + + uint32 header_count; + uint32 unknown_1; + + FileHeader headers[header_count]; + + local int i = 0; + for (i = 0; i < header_count; i++) { + if (headers[i].is_data_file) { + char data_file[headers[i].size]; + } else { + byte data[headers[i].size]; + char data_file[headers[i].len_data_file_name]; + } + } +} File; + +uint32 version ; +uint32 unknown_1; +Assert(unknown_1 == 3); + +uint32 num_entries; +uint64 properties[32] ; + +FileMeta file_meta[num_entries]; + +uint32 num_chunks; +uint32 chunk_sizes[num_chunks]; + +local int padding_size = 16 - (FTell() % 16); +if (padding_size < 16) { + byte padding[padding_size]; +} + +uint32 unpacked_size ; +uint32 unknown_3; + +File files[num_entries] ; \ No newline at end of file diff --git a/dt_chunk.bt b/dt_chunk.bt new file mode 100644 index 0000000..3f4b434 --- /dev/null +++ b/dt_chunk.bt @@ -0,0 +1,21 @@ +//------------------------------------------------ +//--- 010 Editor v12.0.1 Binary Template +// +// File: dt_chunk.dt +// Authors: +// Version: +// Purpose: +// Category: +// File Mask: +// ID Bytes: +// History: +//------------------------------------------------ +uint64 extension_hash ; +uint64 name_hash ; + + // Probably a count, could be the number of file +uint32 unknown_3; + +// Until eof? +// Probably not, because many bundles, even when uncompressed, end with the same/similar trailer +byte data; \ No newline at end of file diff --git a/dt_dds_image.bt b/dt_dds_image.bt new file mode 100755 index 0000000..03f0120 --- /dev/null +++ b/dt_dds_image.bt @@ -0,0 +1,68 @@ +//------------------------------------------------ +//--- 010 Editor v12.0.1 Binary Template +// +// File: +// Authors: +// Version: +// Purpose: +// Category: +// File Mask: +// ID Bytes: +// History: +//------------------------------------------------ + +// ======== +// Typedefs +// ======== + +typedef struct { + unsigned int dxgiFormat; + unsigned int resourceDimension; + unsigned int miscFlag; + unsigned int arraySize; + unsigned int miscFlags2; +} stingray::image::DDSImage::DDS_DX10_HEADER; + + +typedef struct { + unsigned int dwSize; + unsigned int dwFlags; + unsigned int dwFourCC; + unsigned int dwRGBBitCount; + unsigned int dwRBitMask; + unsigned int dwGBitMask; + unsigned int dwBBitMask; + unsigned int dwABitMask; +} stingray::image::DDSImage::DDS_PIXELFORMAT; + +typedef struct +{ + unsigned int dwSize; + unsigned int dwHeaderFlags; + unsigned int dwHeight; + unsigned int dwWidth; + unsigned int dwPitchOrLinearSize; + unsigned int dwDepth; + unsigned int dwMipMapCount; + unsigned int dwReserved1[11]; + stingray::image::DDSImage::DDS_PIXELFORMAT ddspf; + unsigned int dwCaps; + unsigned int dwCaps2; + unsigned int dwReserved2[3]; +} stingray::image::DDSImage::DDS_HEADER; + +// ========= +// Structure +// ========= + +uint32 skip_1; +stingray::image::DDSImage::DDS_HEADER header; + +if (header.ddspf.dwFourCC == 0x30315844) { + stingray::image::DDSImage::DDS_DX10_HEADER dx10_header; +} + +// TODO: Lots of calculations and value checking is done in the code +// before it's determined how to read the next section. +// Though it does look like there are only two ways that it does end up proceeding. +// In the first case, `header.dwDepth` plays a role \ No newline at end of file diff --git a/dt_package.bt b/dt_package.bt new file mode 100644 index 0000000..bf85ebd --- /dev/null +++ b/dt_package.bt @@ -0,0 +1,22 @@ +//------------------------------------------------ +//--- 010 Editor v12.0.1 Binary Template +// +// File: +// Authors: +// Version: +// Purpose: +// Category: +// File Mask: +// ID Bytes: +// History: +//------------------------------------------------ + +uint32 version; +uint32 num_entries; + +typedef struct Entry { + uint64 type ; + uint64 name ; +}; + +Entry entries[num_entries]; \ No newline at end of file diff --git a/dt_strings.bt b/dt_strings.bt new file mode 100644 index 0000000..8ea4516 --- /dev/null +++ b/dt_strings.bt @@ -0,0 +1,22 @@ +//------------------------------------------------ +//--- 010 Editor v12.0.1 Binary Template +// +// File: dt_strings.bt +// Authors: Lucas Schwiderski +// Version: 1.0 +// Purpose: Darktide Strings +// Category: Darktide +// File Mask: *.strings +// ID Bytes: +// History: +//------------------------------------------------ + +uint32 header ; +uint32 count; + +typedef struct { + uint32 name_hash ; + uint32 address ; +} Entry; + +Entry entries[count]; \ No newline at end of file diff --git a/dt_texture.bt b/dt_texture.bt new file mode 100644 index 0000000..d2524db --- /dev/null +++ b/dt_texture.bt @@ -0,0 +1,19 @@ +//------------------------------------------------ +//--- 010 Editor v12.0.1 Binary Template +// +// File: +// Authors: +// Version: +// Purpose: +// Category: +// File Mask: +// ID Bytes: +// History: +//------------------------------------------------ + +uint32 type; + +uint32 compressed_size; +uint32 decompressed_size; + +byte data[compressed_size]; \ No newline at end of file diff --git a/dt_texture_compressed.bt b/dt_texture_compressed.bt new file mode 100644 index 0000000..eaf1b9e --- /dev/null +++ b/dt_texture_compressed.bt @@ -0,0 +1,95 @@ +//------------------------------------------------ +//--- 010 Editor v12.0.1 Binary Template +// +// File: dt_texture_compressed.dt +// Authors: Lucas Schwiderski +// Version: +// Purpose: +// Category: Darktide +// File Mask: +// ID Bytes: +// History: +//------------------------------------------------ + +// The game does ship with two decompression options, but it I've only seen Oodle in the game files +// so far. +// I'd guess `0` is uncompressed, which would only happen in the dev releases, and likely be stripped by `#if`s. +// The compression method does not affect the rest of the data structure +typedef enum { + Oodle = 1, + Custom = 2, +} CompressionType; + +CompressionType compression_type; + +uint32 compressed_size; +uint32 uncompressed_size; + +byte compressed_buffer[compressed_size] ; + +// Skipped by the decompiled binary's code. +// Doesn't fit to be a length of a later data section. It doesn't match anything, and it's an uneven number. +uint32 unknown_1 ; +Assert(unknown_1 == 0x43); + +typedef struct { + uint32 offset; + uint32 size; +} MipInfo; + +typedef struct { + // Checked bits: + // >> 1: Some extra calculations are done with the next three fields around mipmaps + // Also determines if `unknown_2` is saved into `TextureImage` + // => Presumable means "has mipmaps" or VT2's "is streamable" + // >> 2: So far, I haven't found a line of code that actually uses this bit. + // But there is a line that assigns `flags & 3`, indicating that this bit + // does get used somewhere else. + // >> 8: TextureFormat.srgb, probably. + uint32 flags ; + + // Does not match with the number of pairs in `mip_infos`. + uint32 n_streamable_mips; + uint32 width; + uint32 height; + + // Offset and size of mip maps stored in the `.stream` file + // Though it seems that they don't align with mipmaps properly. + // The first size sometimes doesn't include enough data for a full texture + // and it would end up with a black section. + MipInfo mip_infos[16] ; + + uint32 meta_size; +} TextureHeader; + +TextureHeader texture_header; + +// If there is an associated `.stream` file, its content is compressed with Oodle, +// and the numbers in `chunks` below specify the size of each chunk. +// I.e. the `comp_buf_size`, while the `raw_buf_size` is always `0x1000`. +if (texture_header.meta_size > 0) { + uint32 num_chunks; + Assert((num_chunks * 4) + 8 == texture_header.meta_size); + + uint16 unknown_6 ; + Assert(unknown_6 == 0); + + // Always the same as `num_chunks`, but it's weird that this is a u16. + // So probably a different meaning that just happens to be the same value in most/all cases. + uint16 num_chunks_2 ; + Assert(num_chunks == num_chunks_2); + + uint32 chunks[num_chunks]; +} + +// A key to look up a value in the engine's internal render quality settings. +// Specifically, a value that VT2 calls `mip_drop`. +// See `user_settings.conf` -> `texture_settings` +uint32 category ; + +// Shortcuts to get to compile this: +// - `flags = 0` -> skips most of the mipmap stuff in the bundle file +// - `width = 0`, `height = 0` -> also skips some of the mipmap stuff +// - `n_streamable_mipmaps = 0` -> seems to be an intended value to only rely on DDS mipmaps +// It does force `srgb` on through setting a special value for `flags`, though. So if that produces issues, I might +// need to fake it s diff --git a/dt_wwise_bank.bt b/dt_wwise_bank.bt new file mode 100644 index 0000000..7edc166 --- /dev/null +++ b/dt_wwise_bank.bt @@ -0,0 +1,33 @@ +//------------------------------------------------ +//--- 010 Editor v12.0.1 Binary Template +// +// File: dt_wwise_bank.bt +// Authors: Lucas Schwiderski +// Version: +// Purpose: +// Category: Darktide +// File Mask: *.wwise_bank +// ID Bytes: +// History: +//------------------------------------------------ + +uint32 version ; +Assert(version == 0x1b); +uint32 length; + +// A section of values that don't belong the actual Wwise bank +struct { + uint32 unknown1; + Assert(unknown1 == 0x0); + // Matches the file itself + uint64 this_file ; + uint32 unknown2; + Assert(unknown2 == 0x20); + uint32 unknown3; + Assert(unknown3 == 0x0); +} header; + +struct bnk +{ + #include "bnk.bt"; +} wwise_bank ; \ No newline at end of file diff --git a/dt_wwise_event.bt b/dt_wwise_event.bt new file mode 100644 index 0000000..07c6e38 --- /dev/null +++ b/dt_wwise_event.bt @@ -0,0 +1,68 @@ +//------------------------------------------------ +//--- 010 Editor v12.0.1 Binary Template +// +// File: dt_wwise_event.bt +// Authors: Lucas Schwiderski +// Version: +// Purpose: +// Category: Darktide +// File Mask: *.wwise_event +// ID Bytes: +// History: +//------------------------------------------------ + +/*********************************************************************** +File Definition: +***********************************************************************/ + +uint32 version ; +Assert(version == 0x1b); +uint32 length; + +// A section of values that don't belong the actual Wwise bank +struct { + uint32 unknown1; + Assert(unknown1 == 0x0); + // Matches the file itself + uint64 this_file ; + uint32 unknown2; + Assert(unknown2 == 0x40); + uint32 unknown3; + Assert(unknown3 == 0x0); + + // The following hash-like values will probably define some of these values: + // - name of the event + // - Wwise bus the event runs on + + // Corresponds to the `id` value of a HIRC object of type "event" later on in the file + uint32 hirc_event_id ; + + // No particularly clear value. + // Sometimes when interpreted as `float`, it produces whole numbers. + // Sometimes, it's very close to `0xFFFFFFFF`. + uint32 unknown4; + + // Following two usually look like hashes. + // Also often reasonably looking floats close to `1`. Could be something like volume. + // Would still fit with it sometimes showing up elsewhere in a `.wwise_bank`: It's not unreasonable + // for the bnk to have volume values as well. + + // In at least one instance, shows up in `MotionBus`/`MotionFX` sections in a `.wwise_bank`. + uint32 unknown5 ; + // At least in one instance, this was identical with `unknown6` + uint32 unknown6 ; + + uint32 unknown7; + Assert(unknown7 == 0x0 || unknown7 == 0x1); + uint32 unknown8; + Assert(unknown8 == 0x0 || unknown8 == 0x1); + uint32 unknown9; + Assert(unknown9 == 0x0); + uint32 unknown10; + Assert(unknown10 == 0x0); +} header; + +struct bnk +{ + #include "bnk.bt"; +} wwise_bank ; \ No newline at end of file diff --git a/dt_wwise_stream.bt b/dt_wwise_stream.bt new file mode 100755 index 0000000..42d2671 --- /dev/null +++ b/dt_wwise_stream.bt @@ -0,0 +1,22 @@ +//------------------------------------------------ +//--- 010 Editor v12.0.1 Binary Template +// +// File: dt_wwise_stream.bt +// Authors: Lucas Schwiderski +// Version: +// Purpose: +// Category: Darktide +// File Mask: *.wwise_stream +// ID Bytes: +// History: +//------------------------------------------------ + +// Could be the version, but 27 different versions of a file that only contains an offset seems unlikely +uint32 unknown1; +Assert(unknown1 == 0x1b); + +// Offset and length of the section within the `.stream` file. +// Since all `.wwise_stream` files seem to get their own `.stream` file, `offset` always ends up being `0`, +// and `length` always ends up matching the `.stream` file's size. +uint32 offset; +uint32 length; \ No newline at end of file diff --git a/vt2_bundle.bt b/vt2_bundle.bt new file mode 100644 index 0000000..75c4cbe --- /dev/null +++ b/vt2_bundle.bt @@ -0,0 +1,47 @@ +//------------------------------------------------ +//--- 010 Editor v10.0 Binary Template +// +// File: +// Authors: +// Version: +// Purpose: Vermintide 2 Decompressed Bundle +// Category: Vermintide 2 +// File Mask: +// ID Bytes: +// History: +//------------------------------------------------ +typedef struct { + uint64 type ; + uint64 name ; + uint32 padding; + // Data size for all versions combined + uint32 data_size; +} Metadata; + +typedef struct { + uint32 lang; + uint32 size; + uint32 stream_size; +} FileVersion; + +typedef struct { + uint64 type ; + uint64 name ; + uint32 version_count; + uint32 stream_offset; + FileVersion versions[version_count]; + + local int i = 0; + for (i = 0; i < version_count; i++) { + struct FileData { + uchar data[versions[i].size]; + } file_data; + } +} File; + + +uint32 item_count; +uint64 properties[32] ; + +Metadata items[item_count]; +File files[item_count] ; \ No newline at end of file diff --git a/vt2_compressed_bundle.bt b/vt2_compressed_bundle.bt new file mode 100644 index 0000000..7a1be2f --- /dev/null +++ b/vt2_compressed_bundle.bt @@ -0,0 +1,38 @@ +//------------------------------------------------ +//--- 010 Editor v10.0 Binary Template +// +// File: +// Authors: +// Version: +// Purpose: Vermintide 2 Compressed Bundle +// Category: Vermintide 2 +// File Mask: +// ID Bytes: +// History: +//------------------------------------------------ +uint32 format ; +uint32 inflate_size; + +uint32 padding ; + +typedef struct { + uint32 block_size; + uchar data[block_size]; +} Block ; + +string ReadBlock(Block &block) +{ + if(exists(block.block_size)) { + string s; + SPrintf(s, "%lg", block.block_size); + return s; + } else { + return ""; + } +} + + +// No clue how to do "until there is nothing left" with this, so I'll just make up a number +// This is good enough to show the concept anyways +local uint block_count = 100; +Block blocks[block_count] ; \ No newline at end of file diff --git a/vt2_level.bt b/vt2_level.bt new file mode 100644 index 0000000..8d2f6fe --- /dev/null +++ b/vt2_level.bt @@ -0,0 +1,126 @@ +//------------------------------------------------ +//--- 010 Editor v12.0.1 Binary Template +// +// File: vt2_level.bt +// Authors: Lucas Schwiderski +// Version: +// Purpose: +// Category: Vermintide 2 +// File Mask: *.level +// ID Bytes: B5 00 00 00 +// History: +//------------------------------------------------ +// See + +typedef struct { + float x; + float y; + float z; +} Vector3; + +typedef struct { + float x; + float y; + float z; + float w; +} Quaternion; + +typedef struct { + uint32 unknown_1 ; + uint32 unknown_2 ; + // unknown before this + // maps directly to the keys of the same name, as murmur64 hashes + uint64 id_hash ; // has to be there + uint64 name_hash ; // Will be `0x0` when no name was given + uint64 type_hash ; // has to be there + uint64 material_hash ; // will be `0x0` when not given + + // defaults to 0, 0, 0 + Vector3 pos; + // defaults to 0, 0, 0, 0 + Quaternion rot; + // Not sure why they felt the need to abbreviate "scale". Defaults to 1, 1, 1 + Vector3 scl; + // unknown after this +} Unit; + +typedef struct { + uint32 name ; // murmur64-half + uint64 resource ; // murmur64 +} Material; + +typedef struct { + uint32 unit_id; + uint32 num_materials; + + Material materials[num_materials]; +} UnitMaterials; + +// File Parsing + +uint32 version ; // correct +uint32 num_units; // correct +uint32 num_background_units; // correct + +uint32 section_address_unit_data ; //Unit Data & Level Settings +uint32 section_address_unknown1 ; +uint32 section_address_prototypes ; +uint32 section_address_prototypes_data_size ; //Or adress to prototypes collision +uint32 section_address_unknown2 ; +uint32 section_address_unknown3 ; +uint32 section_address_unknown4 ; +uint32 section_address_unknown5 ; +uint32 section_address_unknown6 ; +uint32 section_address_unknown7 ; +uint32 section_address_unknown8 ; +uint32 section_address_level_settings ; +uint32 particles_count; +uint32 section_address_particles ; +uint32 section_address_unknown12 ; +uint32 section_address_unknown13 ; +uint32 section_address_unknown14 ; +uint32 section_address_unknown15 ; +uint32 section_address_unknown16 ; +uint32 section_address_unknown17 ; +uint32 section_address_unknown18 ; +uint32 section_address_unknown19 ; +uint32 section_address_unknown20 ; +uint32 section_address_unknown21 ; +uint32 section_address_unknown22 ; +uint32 section_address_stories ; +uint32 section_address_unknown24 ; +uint32 section_address_unknown25 ; +uint32 section_address_unknown26 ; +uint32 section_address_unknown27 ; +uint32 section_address_unknown28 ; +uint32 section_address_unknown29 ; +uint32 section_address_unit_materials ; +uint32 section_address_unknown31 ; +uint32 section_address_unknown32 ; +uint32 section_address_unknown33 ; + +uint32 num_settings_entries; + +// section start: unit, position unknown: +Unit units[num_units]; + +FSeek(section_address_unit_materials); +uint32 num_unit_materials; +UnitMaterials unit_materials[num_unit_materials]; + +// section end + +uint32 len_sound_environment; // position unknown +byte sound_environment[len_sound_environment]; + +if (len_sound_environment < 4) { + byte padding_1[4 - (len_sound_environment % 4)]; // guess +} +byte unknown_3[3 * 4]; + +uint32 len_timpani_sound_environment; // position unknown +byte timpani_sound_environment[len_timpani_sound_environment]; + +if (len_timpani_sound_environment < 4) { + byte padding_2[4 - (len_timpani_sound_environment % 4)]; // guess +} \ No newline at end of file diff --git a/vt2_nav_data.bt b/vt2_nav_data.bt new file mode 100644 index 0000000..0af3bb2 --- /dev/null +++ b/vt2_nav_data.bt @@ -0,0 +1,101 @@ +//------------------------------------------------ +//--- 010 Editor v11.0.1 Binary Template +// +// File: vt2_nav_data.bt +// Authors: Lucas Schwiderski +// Version: +// Purpose: +// Category: Vermintide 2 +// File Mask: *.(NavData|nav_data) +// ID Bytes: 42 6C 6F 62 41 67 67 46 69 6C 65 00 +// History: +//------------------------------------------------ + +string file_type; +uint32 unknown_1; +if (unknown_1 != 0) + return "Unexpected value"; + + +// Equals `02` for empty.level, `03` for all others so far +// The empty level was missing a section, so that's likely the count for it +uint32 count_sections; + +// TODO: Create an enum for section types and make this section stuff proper +struct { + uint32 section_1_type; + if (section_1_type != 0x0500) + return "Unexpected value"; + + uint32 unknown_4; + if (unknown_4 != 0) + return "Unexpected value"; + + + // Both always `0x28` + uint32 unknown_5; + uint32 unknown_6; + + uint32 build_string_length; + + // Always `0x04` + uint32 unknown_8; + + char build_string[build_string_length]; + + // Padding to get `build_string_length` to divide by 4 (technically `sizeof(uint32)`) + if (build_string_length % 4 != 0) { + byte build_string_padding[4 - (build_string_length % 4)]; + } +} Header; + +uint32 section_2_type; +if (section_2_type == 0x01) { + + uint32 count_nav_meshes; + + struct NavMesh { + uint32 data_length; + // Could be length of the following section + uint32 section_length; + + byte data[data_length]; + } nav_meshes[count_nav_meshes] ; + + uint32 section_3_type; +} + +uint32 unknown_12; +// For any non-empty navdata, this seems to increas by 4 +uint32 unknown_13; +// Seems to be always the same as `unknown_13` +uint32 unknown_14; +uint32 unknown_15; +uint32 unknown_16; +uint32 unknown_17; +uint32 unknown_18; +uint32 unknown_19; +uint32 unknown_20; +uint32 unknown_21; +uint32 unknown_22; + +// Not actually null-terminated +char header_sector_descriptor[16]; + +struct SectorDescriptor{ + uint32 unknown_1; + uint32 sector_name_header_length; + uint32 unknown_3; + uint32 sector_name_value_length; + uint32 generator_type_name_length; + uint32 unknown_6; + uint32 unknown_7; + uint32 unknown_8; + uint32 unknown_9; +} sector_descriptor; + +// Terminated by two! nulls +char header_sector_name[sector_descriptor.sector_name_header_length]; +// Padding to get string length to divide by 4 (technically `sizeof(uint32)`) +byte header_sector_name_padding[4 - (sector_descriptor.sector_name_header_length % 4)]; +string sector_name; \ No newline at end of file diff --git a/vt2_network_config.bt b/vt2_network_config.bt new file mode 100644 index 0000000..0e58425 --- /dev/null +++ b/vt2_network_config.bt @@ -0,0 +1,40 @@ +//------------------------------------------------ +//--- 010 Editor v11.0.1 Binary Template +// +// File: vt2_network_config.bt +// Authors: Lucas Schwiderski +// Version: +// Purpose: +// Category: Vermintide 2 +// File Mask: *.network_config +// ID Bytes: 20 00 00 00 +// History: +//------------------------------------------------ +typedef enum { + PeerToPeer, + ClientServer +} NetworkType; + +typedef enum { + Int = 0x01, + Int64 = 0x07, + GamerObjectId = 0x34 +} Primitive; + +typedef struct { + Primitive primitive; + uint16 bits; + uint32 padding; + uint32 name_hash; + uint32 tolerance; + uint32 min; // Possibly 'min' for number values + uint32 max; +} Type; + +uint32 version; +NetworkType network_type; +uint32 reliable_send_buffer_size; +uint32 reliable_receive_buffer_size; + +uint32 num_types ; +Type types[num_types]; \ No newline at end of file diff --git a/vt2_network_config_new.bt b/vt2_network_config_new.bt new file mode 100644 index 0000000..f5a4cc1 --- /dev/null +++ b/vt2_network_config_new.bt @@ -0,0 +1,92 @@ +//------------------------------------------------ +//--- 010 Editor v11.0.1 Binary Template +// +// File: vt2_network_config_new.bt +// Authors: Lucas Schwiderski +// Version: +// Purpose: +// Category: Vermintide 2 +// File Mask: *.network_config +// ID Bytes: 23 00 00 00 +// History: +//------------------------------------------------ + +typedef enum { + Bool, + Int, + Float, + Vector3, + Quaternion, + String, + Int64 = 0x07, + Array, + GamerObjectId = 0x34 +} Primitive; + +typedef struct { + uint32 name_hash; + uint32 padding; + uint32 data_1; + Primitive primitive; + uint16 bits; + byte unknown_1; + uint32 min; // Possibly 'min' for number values + uint32 max; +} Type; + +typedef struct { + uint32 index; +} ObjectField; + +typedef struct { + uint32 index; +} ObjectFieldType; + +typedef struct { + uint32 name; +} ObjectFieldName; + +typedef struct { + uint32 name_hash; + uint32 unknown_1; + uint32 unknown_2; + float priority; + float update_rate; + uint32 num_field_types ; + ObjectFieldType object_field_types[num_field_types]; + uint32 num_field_names ; + if (num_field_names != num_field_types) + return "Number of objects types and names doesn't match"; + ObjectFieldName object_field_names[num_field_names]; +} Object; + +// Templates don't support defining an array of null-terminated strings, +// so we need to wrap it into a struct +typedef struct { + string name; +} ObjectName; + +uint32 version; +uint32 reliable_send_buffer_size; +uint32 reliable_receive_buffer_size; + +uint32 num_types ; +Type types[num_types]; + +uint32 num_object_names ; +uint16 object_start_positions[num_object_names] ; +uint32 total_names_length ; + +// By default the array would be optimized to truncate every entry +// to the length of the first one. +ObjectName object_names[num_object_names]