Last active
August 14, 2020 11:10
-
-
Save BenChampion/96d6b18fc60c88a5b513c7be483de6d9 to your computer and use it in GitHub Desktop.
Incomplete parser for R3D HOB file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from construct import \ | |
Int8ul, Int16ul, Int16ub, Int16sl, Int32ul, \ | |
Float32l, \ | |
Struct, AlignedStruct, Array, Aligned, Sequence, \ | |
RepeatUntil, GreedyRange, \ | |
this, len_, obj_,\ | |
Byte, Bytes, Const, \ | |
Bitwise, BitStruct, Flag, BitsInteger, \ | |
If, IfThenElse, Select,\ | |
Tell, Computed, Check, \ | |
Pointer, \ | |
Probe, RawCopy, HexDump # can debug by putting a "Probe()" as a parser field | |
Object = \ | |
Struct( | |
"name" / Bytes(16), | |
"object_parts_offset" / Int32ul, | |
"object_parts_header_offset" / Int32ul, | |
"object_subparts_header_offset" / Int32ul, | |
"UNKNOWN_header_offset" / HexDump(RawCopy(Int32ul)), # in e.g. imp_stuff/tieinter_HOB, not zero; | |
"UNKNOWN_header_2_offset" / HexDump(RawCopy(Int32ul)), # instead, offsets to another object header | |
# just after the 0xFFFFFFFF end of first one (?) | |
Const([0]*4, Int8ul[4]), | |
"object_parts_names_offset" / Int32ul, | |
"object_effects_offset" / Int32ul, | |
"UNKNOWN_offset_1" / HexDump(RawCopy(Int32ul)), | |
"UNKNOWN_float" / Float32l, | |
Const([0]*12, Int8ul[12]), | |
"UNKNOWN_floats" / Array(5, Float32l), | |
"offset_to_8_bytes_before_bounding_box_before_end_of_header_marker" / Int32ul, | |
"bounding_box" / Array(6, Float32l) | |
) | |
ObjectDefinition = \ | |
Struct( | |
"object_parts_header" / | |
Struct( | |
"number_of_object_parts" / Int16ul, | |
"number_of_object_subparts" / Int16ul, | |
"object_parts_offsets" / | |
Array(this.number_of_object_parts, | |
Struct( | |
"UNKNOWN_maybe_2_Int16ul" / HexDump(RawCopy(Int16ul[2])), | |
"object_part_meshdef0_offset" / Int32ul | |
) | |
), | |
), | |
"object_subparts_header" / | |
Struct( | |
"number_of_object_parts" / Int16ul, | |
"number_of_object_subparts" / Int16ul, | |
"object_subparts_definition" / | |
Array(this.number_of_object_parts, | |
Struct( | |
"object_subparts_meshdef1_offsets" / RepeatUntil(obj_ == 0, Int32ul), | |
"number_of_subparts_this_part" / Computed(len_(this.object_subparts_meshdef1_offsets) - 1) | |
) | |
), | |
), | |
"named_object_parts" / | |
Aligned(4, | |
RepeatUntil(obj_ == 0, | |
Select( | |
Const(0,Int32ul), | |
Struct( | |
"name" / Bytes(8), | |
"object_index" / Int16ub | |
) | |
) | |
) | |
), | |
"object_effects" / | |
RepeatUntil(obj_ == 0, | |
Select( | |
Const(0,Int32ul), | |
Struct( | |
"meshdef1_offset_plus_4" / Int32ul, | |
"name" / Bytes(6), | |
"object_index" / Int16ub | |
) | |
) | |
), | |
"UNKNOWN_matrices" / | |
RepeatUntil(obj_ == 0, | |
Select( | |
Const(0, Int32ul), | |
Struct( | |
"name" / Bytes(6), | |
"maybe_object_index" / HexDump(RawCopy(Int8ul)), | |
"number_of_matrices" / Int8ul, | |
"matrices" / Float32l[9][this.number_of_matrices] | |
) | |
) | |
), | |
"bounding_boxes" / | |
RepeatUntil(obj_ == b"\xff\xff\xff\xff", | |
Select( | |
Const(b"\xff\xff\xff\xff",Bytes(4)), | |
Struct( | |
"unknown_maybe_0_or_1" / Int32ul, | |
"bounding_box" / Float32l[6] | |
) | |
) | |
), | |
) | |
Meshdef0 = \ | |
Struct( | |
"mostly_offset_to_next" / Int32ul, | |
"maybe_offset_to_prev" / Int32ul, | |
"maybe_mostly_offset_to_beginning" / Int32ul, | |
"offset_to_end_if_no_next" / Int32ul, | |
"offset_to_meshdef1_plus_4" / Int32ul, | |
Const([0]*8, Int8ul[8]), | |
Array(3, | |
Struct( | |
Float32l, | |
Const([0]*12, Int8ul[12]) | |
) | |
), | |
"UNKNOWN_int" / HexDump(RawCopy(Int32ul)), | |
"UNKNOWN_floats_1" / Float32l[3], | |
"UNKNOWN_floats_2" / Float32l[3], | |
"UNKNOWN_floats_3" / Float32l[4], | |
"maybe_relative_translation" / Float32l[3], | |
) | |
Meshdef1 = \ | |
Struct( | |
"facedef_end_offset" / Int32ul, | |
"UNKNOWN_maybe_offset_to_next" / Int32ul, | |
"UNKNOWN_maybe_offset_to_prev" / Int32ul, | |
Const([0]*12, Int8ul[12]), | |
"vertex_count" / Int32ul, | |
"UNKNOWN_int" / Int32ul, | |
Const(0, Int32ul), | |
"face_block_offset" / Int32ul, | |
"vertex_block_offset" / Int32ul, | |
"UNKNOWN_offset" / Int32ul, | |
Const([0]*48, Int8ul[48]), | |
) | |
Color = \ | |
Struct( | |
"R" / Int8ul, | |
"G" / Int8ul, | |
"B" / Int8ul, | |
"A" / Int8ul | |
) | |
Face = \ | |
Struct( | |
"flags" / | |
BitStruct( | |
"bit07_UNKNOWN" / Flag, | |
"bit06_has_extra_8_bytes" / Flag, | |
"bit05_has_color" / Flag, | |
"bit04_has_vertex_colors" / Flag, | |
"bit03_is_quad" / Flag, | |
"bit02_has_texture_coords" / Flag, | |
"bit01_UNKNOWN" / Flag, | |
"bit00_UNKNOWN" / Flag, | |
"bit15_UNKNOWN_seems_unset" / Flag, | |
"bit14_UNKNOWN_seems_unset" / Flag, | |
"bit13_UNKNOWN_seems_unset" / Flag, | |
"bit12_UNKNOWN_seems_unset" / Flag, | |
"bit11_UNKNOWN_seems_unset" / Flag, | |
"bit10_UNKNOWN" / Flag, # may be associated with an extra 8 bytes | |
"bit09_UNKNOWN" / Flag, # may be associated with an extra 8 bytes | |
"bit08_UNKNOWN" / Flag, | |
), | |
"UNKNOWN_bits_seem_unset" / Const(0,Int16ul), | |
"UNKNOWN_byte_1" / Int8ul, | |
"UNKNOWN_byte_2" / Int8ul, | |
"UNKNOWN_byte_3" / Int8ul, | |
"face_struct_size_in_4_byte_words" / Int8ul, | |
Const(0, Int16ul), | |
"material_index" / Int16ul, | |
"vertex_indices" / Int16ul[4], | |
# all DEBUG sizes in 4 byte words | |
"DEBUG_FIXED_PARTS_SIZE" / Computed(5), | |
"DEBUG_EXTRA_8_BYTES_SIZE" / Computed(lambda this: 2 if this.flags.bit06_has_extra_8_bytes else 0), | |
"DEBUG_COLOR_SIZE" / | |
Computed( | |
lambda this: | |
( | |
(4 if this.flags.bit03_is_quad else 3) if this.flags.bit04_has_vertex_colors else 1 | |
) | |
if this.flags.bit05_has_color | |
else 0 | |
), | |
"DEBUG_TEXTURE_COORDS_SIZE" / | |
Computed( | |
lambda this: | |
(4 if this.flags.bit03_is_quad else 3) | |
if this.flags.bit02_has_texture_coords | |
else 0 | |
), | |
"DEBUG_COMPUTED_TOTAL_SIZE" / | |
Computed( | |
lambda this: | |
this.DEBUG_FIXED_PARTS_SIZE + | |
this.DEBUG_EXTRA_8_BYTES_SIZE + | |
this.DEBUG_COLOR_SIZE + | |
this.DEBUG_TEXTURE_COORDS_SIZE | |
), | |
Check(this.DEBUG_COMPUTED_TOTAL_SIZE <= this.face_struct_size_in_4_byte_words), | |
"face_data" / | |
IfThenElse(this.DEBUG_COMPUTED_TOTAL_SIZE == this.face_struct_size_in_4_byte_words, | |
Struct( | |
"UNKNOWN_extra_8_bytes" / | |
If(this._.flags.bit06_has_extra_8_bytes, Byte[8]), | |
"color" / | |
If(this._.flags.bit05_has_color, | |
IfThenElse(this._.flags.bit04_has_vertex_colors, | |
Color[lambda this: 4 if this._.flags.bit03_is_quad else 3], | |
Color | |
), | |
), | |
"texture_coords" / | |
If(this._.flags.bit02_has_texture_coords, | |
Array(lambda this: 4 if this._.flags.bit03_is_quad else 3, | |
Struct( | |
"u" / Int16sl, | |
"v" / Int16sl | |
) | |
) | |
) | |
), | |
Struct( | |
"size_mismatch_unknown_flags_raw_bytes" / | |
HexDump(RawCopy(Byte[lambda this: 4*(this._.face_struct_size_in_4_byte_words - this._.DEBUG_FIXED_PARTS_SIZE) ])) | |
) | |
) | |
) | |
FaceBlock = \ | |
Struct( | |
Const([0]*8, Int8ul[8]), | |
"current_file_pos" / Tell, | |
"current_file_pos_plus_4" / Int32ul, | |
"face_count" / Int32ul, | |
"faces" / Face[this.face_count] | |
) | |
Vertex = \ | |
Struct( | |
"x" / Int16sl, | |
"y" / Int16sl, | |
"z" / Int16sl, | |
"maybe_padding" / Const(0,Int16sl) | |
) | |
HOBFile = \ | |
Struct( | |
"object_count" / Int32ul, | |
"offset_to_faces_and_vertices" / Int32ul, | |
"object_data" / | |
Array( | |
this.object_count, | |
Struct( | |
"object_header" / Object, | |
"object_definition" / Pointer(this.object_header.object_parts_header_offset, ObjectDefinition), | |
"object_composition" / | |
Array( | |
this.object_definition.object_parts_header.number_of_object_parts, | |
Struct( | |
"meshdef0" / | |
Pointer(lambda this: | |
this._.object_definition.object_parts_header. | |
object_parts_offsets[this._index].object_part_meshdef0_offset, | |
Meshdef0 | |
), | |
"subparts" / | |
Array(lambda this: | |
this._.object_definition.object_subparts_header. | |
object_subparts_definition[this._index].number_of_subparts_this_part, | |
Struct( | |
"meshdef1" / | |
Pointer(lambda this: | |
this._._.object_definition.object_subparts_header. | |
object_subparts_definition[this._._._index]. | |
object_subparts_meshdef1_offsets[this._._index] - 4, | |
Meshdef1 | |
), | |
"face_block" / | |
Pointer( | |
this.meshdef1.face_block_offset, | |
FaceBlock | |
), | |
"vertex_block" / | |
Pointer( | |
this.meshdef1.vertex_block_offset, | |
Struct( | |
Array( | |
this._.meshdef1.vertex_count, | |
Struct( | |
"vertex" / Vertex | |
) | |
), | |
) | |
), | |
) | |
) | |
) | |
) | |
) | |
) | |
) | |
# Y level/lv_X/opkg_HOB", X = 1..9 a...i (j has empty opkg) | |
# Y box_HOB | |
# Y dbg/dbg_HOB | |
# Y pl_crafts/xwing_HOB | |
# Y pl_crafts/falcon_HOB | |
# (Y all pl_crafts tried, including wm crafts and cockpits) | |
# (Y imp_stuff/tieinter_HOB) | |
# (Y ../data2/koelsch_HOB) | |
# (Y weapons_HOB) | |
with open("../../unpacked_DATA/data/dbg/dbg_HOB","rb+") as f: | |
result = HOBFile.parse_stream(f) | |
print(result) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment