#pragma once #include #include #include #include #include "common/common_types.h" #include "common/math/Vector.h" #include "common/versions/versions.h" #include "decompiler/level_extractor/common_formats.h" #include "decompiler/util/goal_data_reader.h" namespace decompiler { class LinkedObjectFile; class DecompilerTypeSystem; } // namespace decompiler namespace level_tools { struct PrintSettings { bool print_tfrag = false; bool expand_draw_node = false; bool expand_drawable_tree_tfrag = false; bool expand_drawable_tree_trans_tfrag = false; bool expand_drawable_tree_tie_proto = false; bool expand_drawable_tree_tie_proto_data = false; bool expand_drawable_tree_instance_tie = false; bool expand_drawable_tree_actor = false; bool expand_shrub = false; bool expand_collide = false; }; ///////////////////// // Common Types ///////////////////// // a normal vector of 4 floats. struct Vector { float data[4]; void read_from_file(Ref ref); std::string print(int indent = 0) const; std::string print_meters(int indent = 0) const; std::string print_decimal(int indent = 0) const; }; // a matrix with 16-bit integers. // typically requires some unpacking step to get meaningful values. struct Matrix4h { u16 data[16]; void read_from_file(Ref ref); }; // A time-of-day color palette. // this is just the raw data, doesn't have any unpacking/meaning. struct TimeOfDayPalette { u32 width; u32 height; u32 pad; std::vector colors; void read_from_file(Ref ref); }; ///////////////////// // Drawable BVH ///////////////////// // these types are all generic container types/base classes. // note that the unpacker just greedily chases things and doesn't deduplicate, so comparing // pointers for equality won't tell you if two things are the same game object or not. // the base class for everything in the BVH tree system. struct Drawable { virtual void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) = 0; virtual std::string print(const PrintSettings& settings, int indent) const = 0; virtual std::string my_type() const = 0; virtual ~Drawable() = default; }; // a node in the BVH tree. It's just used for organizing things within a bsphere. // these nodes are always in inline arrays and have between 0 and 8 children. // the leaves of these nodes are some other type of drawable - the thing you actually want to draw. struct DrawNode : public Drawable { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override; s16 id; Vector bsphere; u8 child_count = 0; u8 flags = 0; std::vector> children; float distance = 0; }; // an inline array of drawable. There are more specific types for the actual arrays. struct DrawableInlineArray : public Drawable {}; // an inline array of draw nodes. All draw nodes at a level are stored in a drawable inline array. struct DrawableInlineArrayNode : public DrawableInlineArray { s16 id; s16 length; Vector bsphere; std::vector draw_nodes; void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override; }; // the generic base class for a "tree". A tree is a BVH with between 1 and 8 DrawNode roots. // there's typically a tree per renderer. struct DrawableTree : public Drawable {}; // how we represent drawable trees that we don't support yet - this isn't a real type in the game. struct DrawableTreeUnknown : public DrawableTree { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override; std::string type_name; }; struct DrawableInlineArrayUnknown : public DrawableInlineArray { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override; std::string type_name; }; ///////////////////// // Actors ///////////////////// // there's a tree for actors - but we don't do anything with it yet. constexpr float kDefaultKeyFrame = -1000000000.f; struct Res { std::string name; float key_frame = -2; std::string elt_type; u16 count; bool inlined = false; std::vector inlined_storage; std::vector strings; goos::Object script; }; struct EntityActor { Vector trans; u32 aid = 0; // nav mesh std::string etype; int task = 0; u16 vis_id = 0; Vector quat; std::vector res_list; void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version); }; struct DrawableActor : public Drawable { Vector bsphere; EntityActor actor; void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override { return "drawable-actor"; } }; struct DrawableTreeActor : public DrawableTree { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override; s16 id; s16 length; // todo time of day stuff Vector bsphere; std::vector> arrays; }; ///////////////////// // Collision ///////////////////// struct CollideFragMesh { /* ((packed-data uint32 :offset-assert 4) (pat-array uint32 :offset-assert 8) (strip-data-len uint16 :offset-assert 12) (poly-count uint16 :offset-assert 14) (base-trans vector :inline :offset-assert 16) ;; these go in the w of the vector above. (vertex-count uint8 :offset 28) (vertex-data-qwc uint8 :offset 29) (total-qwc uint8 :offset 30) (unused uint8 :offset 31) ) */ void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts); std::string print(const PrintSettings& settings, int indent) const; u16 strip_data_len; u16 poly_count; // appears to be integers... Vector base_trans; u8 vertex_count; u8 vertex_data_qwc; u8 total_qwc; Ref packed_data; Ref pat_array; }; struct CollideFragment { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts); std::string print(const PrintSettings& settings, int indent) const; Vector bsphere; CollideFragMesh mesh; }; struct DrawableInlineArrayCollideFragment : public DrawableInlineArray { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override; std::vector collide_fragments; s16 id; s16 length; Vector bsphere; }; struct DrawableTreeCollideFragment : public DrawableTree { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override; DrawableInlineArrayCollideFragment last_array; }; ///////////////////// // TFRAG ///////////////////// struct TFragmentDebugData { u16 num_tris[4]; u16 num_dverts[4]; bool has_debug_lines; std::string print(int indent) const; void read_from_file(Ref ref, const decompiler::DecompilerTypeSystem& dts); }; // the "fragment" is just a collection of data that fits into the VU memory. struct TFragment : public Drawable { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override { return "tfragment"; } // 0 - 4 type tag s16 id; // 4 - 6 u16 color_index; // 6 - 8 TFragmentDebugData debug_data; // u32 color_indices; // 12 - 16 (or colors?) Vector bsphere; // 16 - 32 // dma common/level0 // 32 - 36 std::vector dma_common_and_level0; // dma base // 36 - 40 std::vector dma_base; // dma level 1 // 40 - 44 std::vector dma_level1; std::vector color_indices; u8 dma_qwc[4]; // shader // 48 - 52 u8 num_shaders; // 52 u8 num_base_colors; // 53 u8 num_level0_colors; // 54 u8 num_level1_colors; // 55 u8 color_offset; // 56 u8 color_count; // 57 // u8 pad0; // 58 // u8 pad1; // 59 // generic // 60 - 64 }; // array of tfragments. This is used as part of the BVH tree struct DrawableInlineArrayTFrag : public DrawableInlineArray { s16 id; s16 length; Vector bsphere; std::vector tfragments; void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override; }; // a top-level tfragment tree. // it has a BVH tree of tfragments as well as a time of day palette. struct DrawableTreeTfrag : public DrawableTree { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override; s16 id; s16 length; TimeOfDayPalette time_of_day; Vector bsphere; std::vector> arrays; }; // various specializations of tfragment. struct DrawableTreeTransTfrag : public DrawableTreeTfrag { std::string my_type() const override { return "drawable-tree-trans-tfrag"; } }; struct DrawableTreeLowresTfrag : public DrawableTreeTfrag { std::string my_type() const override { return "drawable-tree-lowres-tfrag"; } }; struct DrawableTreeDirtTfrag : public DrawableTreeTfrag { std::string my_type() const override { return "drawable-tree-dirt-tfrag"; } }; struct DrawableTreeIceTfrag : public DrawableTreeTfrag { std::string my_type() const override { return "drawable-tree-ice-tfrag"; } }; struct DrawableInlineArrayTransTFrag : public DrawableInlineArrayTFrag { std::string my_type() const override { return "drawable-inline-array-trans-tfrag"; } }; struct DrawableInlineArrayTFragTrans : public DrawableInlineArrayTFrag { std::string my_type() const override { return "drawable-inline-array-tfrag-trans"; } }; struct DrawableInlineArrayTFragWater : public DrawableInlineArrayTFrag { std::string my_type() const override { return "drawable-inline-array-tfrag-water"; } }; struct DrawableTreeTfragTrans : public DrawableTreeTfrag { std::string my_type() const override { return "drawable-tree-tfrag-trans"; } }; struct DrawableTreeTfragWater : public DrawableTreeTfrag { std::string my_type() const override { return "drawable-tree-tfrag-water"; } }; ///////////////////// // TIE ///////////////////// // a tie-fragment is a chunk of geometry that can be sent to the VU. // it's similar to a tfragment, but a bit simpler. // each prototype is made up of fragments. struct TieFragment : public Drawable { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override { return "tie-fragment"; } Vector bsphere; u16 num_tris; u16 num_dverts; u16 tex_count; u16 gif_count; u16 vertex_count; // qwc of vertex data. std::vector gif_data; std::vector point_ref; std::string debug_label_name; std::vector normals; // jak 2 std::vector generic_data; // jak 1 // todo, lots more }; // represents an instance of a prototype. // each instance has its own color data, but the rest of the geometry/texture is shared between // all instances of the same prototype. struct InstanceTie : public Drawable { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override { return "instance-tie"; } // (bucket-index uint16 :offset 6) u16 bucket_index; // which prototype s16 id; Vector bsphere; // where we are located Matrix4h origin; u16 flags; u16 wind_index; Ref color_indices; // can't read this in the first pass because we don't know how long. // todo, lots more }; // a prototype is basically just a collection of fragments struct PrototypeTie : public DrawableInlineArray { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override; s16 id; s16 length; Vector bsphere; std::vector tie_fragments; }; // a prototype bucket is a collection of 4 different prototypes (called geometries), one for each // level of detail. All geometries share the same time of day palette. // the bucket also refers to the fact that it collect instances during actual rendering. // Note: collision extraction is only supported in jak 1. struct PrototypeBucketTie { std::string name; // 4 - 8 u32 flags; // 8 - 12 u16 in_level; // 12 - 14 u16 utextures; // 14 - 16 PrototypeTie geometry[4]; Vector dists; Vector rdists; u32 next[4]; u16 count[4]; // u16 generic_count[4]; // u32 generic_next[4]; u8 frag_count[4] = {0}; u8 index_start[4]; u16 base_qw[4]; float envmap_rfade; float envmap_fade_far; float stiffness; std::vector color_index_qwc; TimeOfDayPalette time_of_day; bool has_envmap_shader = false; u8 envmap_shader[5 * 16]; math::Vector jak2_tint_color; // jak 2 only // todo collide-frag DrawableInlineArrayCollideFragment collide_frag; std::vector collide_hash_frags; // jak 2 only // todo tie-colors // todo data void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version); std::string print(const PrintSettings& settings, int indent) const; }; // an array of all the prototypes. The prototypes aren't stored in a BVH (it wouldn't make sense - // they can be located all over the place)- there is just a plain array. struct PrototypeArrayTie { u32 length; u32 allocated_length; std::string content_type; std::vector data; void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version); std::string print(const PrintSettings& settings, int indent) const; }; // the reason for this type is somewhat unknown, but it just contains the prototype array and // wind vectors. The wind vector data is all 0's and is updated as the game runs. struct ProxyPrototypeArrayTie { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version); std::string print(const PrintSettings& settings, int indent) const; PrototypeArrayTie prototype_array_tie; Ref wind_vectors; }; // array of instances. These are part of the BVH struct DrawableInlineArrayInstanceTie : public DrawableInlineArray { s16 id; s16 length; Vector bsphere; std::vector instances; void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override; }; // TIE tree struct DrawableTreeInstanceTie : public DrawableTree { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const PrintSettings& settings, int indent) const override; std::string my_type() const override; s16 id; s16 length; ProxyPrototypeArrayTie prototypes; Vector bsphere; std::vector> arrays; }; ///////////////////////////////// // SHRUB ///////////////////////////////// namespace shrub_types { struct Shrubbery : public level_tools::Drawable { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const level_tools::PrintSettings& settings, int indent) const override; std::string my_type() const override { return "shrubbery"; } // 4 - textures std::vector textures; std::vector header; u8 obj_qwc; // 12 u8 vtx_qwc; // 13 u8 col_qwc; // 14 u8 stq_qwc; // 15 std::vector obj; // 16 std::vector vtx; // 20 std::vector col; // 24 std::vector stq; // 28 }; struct PrototypeShrubbery : public level_tools::DrawableInlineArray { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const level_tools::PrintSettings& settings, int indent) const override; std::string my_type() const override { return "prototype-shrubbery"; } s16 id; // 0 s16 length; // 4 level_tools::Vector bsphere; // 16 std::vector shrubs; // 32 }; struct Billboard {}; struct GenericShrubFragment : public level_tools::Drawable { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const level_tools::PrintSettings& settings, int indent) const override; std::string my_type() const override { return "generic-shrub-fragment"; } // // (textures (inline-array adgif-shader) :score 999 :offset 4) std::vector textures; // (vtx-cnt uint32 :score 999 :offset 8) u32 vtx_cnt; // (cnt-qwc uint8 :score 999 :offset 12) u8 cnt_qwc; // (vtx-qwc uint8 :score 999 :offset 13) u8 vtx_qwc; // (col-qwc uint8 :score 999 :offset 14) u8 col_qwc; // (stq-qwc uint8 :score 999 :offset 15) u8 stq_qwc; // (cnt uint32 :score 999 :offset 16) std::vector cnt; // (vtx uint32 :score 999 :offset 20) std::vector vtx; // (col uint32 :score 999 :offset 24) std::vector col; // (stq uint32 :score 999 :offset 28) std::vector stq; }; // really a drawable-group, but we'll make it drawable here. struct PrototypeGenericShrub : public level_tools::Drawable { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const level_tools::PrintSettings& settings, int indent) const override; std::string my_type() const override { return "prototype-generic-shrub"; } s16 length; // 4 level_tools::Vector bsphere; // 16 std::vector shrubs; // 32 }; struct PrototypeBucketShrub { std::string name; // 4 u32 flags; // 8 u16 in_level; // 12 u16 utextures; // 14 // PrototypeShrubbery geometry[4]; // 16 PrototypeGenericShrub generic_geom; // 0 PrototypeShrubbery shrubbery_geom; // 1 // todo transparent geom // todo billboard geom level_tools::Vector dists; // 32 // - near-plane // - near-stiff // - mid-plane // - far-plane level_tools::Vector rdists; // 48 // - rlength-near // - rlength-stiff // - rlength-mid // - stiffness float stiffness; // - 60 // the next/last/count/mod stuff is all 0's. void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version); std::string print(const level_tools::PrintSettings& settings, int indent) const; }; struct PrototypeInlineArrayShrub { s16 id; // 4 s16 length; // 6 level_tools::Vector bsphere; // 16 std::vector data; // 32 void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version); std::string print(const level_tools::PrintSettings& settings, int indent) const; }; struct PrototypeArrayShrubInfo { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version); std::string print(const level_tools::PrintSettings& settings, int indent) const; PrototypeInlineArrayShrub prototype_inline_array_shrub; Ref wind_vectors; }; struct InstanceShrubbery : public level_tools::Drawable { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const level_tools::PrintSettings& settings, int indent) const override; std::string my_type() const override { return "instance-shrubbery"; } s16 id; // 4 u16 bucket_index; // 6 level_tools::Vector bsphere; // 16 level_tools::Matrix4h origin; // 32 u16 wind_index; // 62 // --- instance-shrubbery --- u32 color_indices; // 8 - unlike tie, I think this is just an integer offset level_tools::Vector flat_normal; // 64 (w is flat_hwidth) }; struct DrawableInlineArrayInstanceShrub : public level_tools::DrawableInlineArray { s16 id; s16 length; level_tools::Vector bsphere; std::vector instances; void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const level_tools::PrintSettings& settings, int indent) const override; std::string my_type() const override { return "drawable-inline-array-instance-shrub"; } }; struct DrawableTreeInstanceShrub : public level_tools::DrawableTree { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version) override; std::string print(const level_tools::PrintSettings& settings, int indent) const override; std::string my_type() const override; s16 id; // 0 s16 length; // 4 PrototypeArrayShrubInfo info; // 8 TimeOfDayPalette time_of_day; level_tools::Vector bsphere; // 16 std::vector> arrays; // annoyingly, the shrub tree only has the top level in the array.... // so we can't use the above "arrays" like we did in tfrag/tie. // luckily, it seems to be possible to figure out the location of the remaining arrays. // so we add this field to hold the arrays we found. // note that the tree format is not quite the same as tfrag/tie - the 8 child max is no longer // true, and the arrays are not truly by depth (the leaves aren't all the same depth) // this means there may be multiple arrays of instances, and we'll need to check all of them. std::vector> discovered_arrays; }; } // namespace shrub_types struct DrawableInlineArrayActor { std::vector drawable_actors; void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version); }; struct CollideHash { Ref item_array; int num_items = 0; void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version); }; /* ((start-corner vector :inline :offset-assert 32) (spheres (inline-array vector) :offset-assert 48) (visids (pointer int16) :offset-assert 52) (shaders (inline-array adgif-shader) :offset-assert 56) (colors time-of-day-palette :offset-assert 60) (montage uint32 :offset-assert 64) (buckets-far (inline-array hfrag-bucket) :offset-assert 68) (buckets-mid (inline-array hfrag-bucket) :offset-assert 72) (buckets-near (inline-array hfrag-bucket) :offset-assert 76) (verts (inline-array hfrag-vertex) :offset-assert 80) ;; wrong type? 8288 (pat-array (pointer pat-surface) :offset-assert 84) (pat-length uint16 :offset-assert 88) (num-buckets-far uint16 :offset-assert 90) (num-buckets-mid uint16 :offset-assert 92) (num-buckets-near uint16 :offset-assert 94) (size uint32 :offset 44 :score 1) */ struct HFragmentMontage { u16 table[16]; }; struct HFragment { void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts); static constexpr int kCornersPerEdge = 32; static constexpr int kNumCorners = kCornersPerEdge * kCornersPerEdge; static constexpr int kVertsPerEdge = 512; static constexpr int kNumVerts = 512 * 512; level_tools::Vector start_corner; // location of corner (0, 0) std::vector spheres; // array of bspheres for each "corner" std::vector vis_ids; // precomputed vis id for each "corner" AdGifData shaders[3]; TimeOfDayPalette colors; HFragmentMontage montage[17]; // buckets?? std::vector verts; // pat-array // pat-length u16 num_buckets_far = 0; u16 num_buckets_mid = 0; u16 num_buckets_near = 0; u32 size = 0; }; //////////////////////////////// // Main Level Type (bsp-header) //////////////////////////////// // all the different trees are stored in a drawable-tree-array. struct DrawableTreeArray { s16 id; s16 length; void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts, GameVersion version); std::string print(const PrintSettings& settings, int indent) const; std::vector> trees; }; // The "file info" struct FileInfo { std::string file_type; std::string file_name; u32 major_version; u32 minor_version; std::string maya_file_name; std::string tool_debug; std::string mdb_file_name; void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts); std::string print(int indent = 0) const; }; struct BspHeader { // (info file-info :offset 4) FileInfo file_info; // (bsphere vector :inline :offset-assert 16) Vector bsphere; // (all-visible-list (pointer uint16) :offset-assert 32) // (visible-list-length int32 :offset-assert 36) s32 visible_list_length = -1; s32 extra_vis_list_length = -1; // jak 2+ only // (drawable-trees drawable-tree-array :offset-assert 40) DrawableTreeArray drawable_tree_array; // (pat pointer :offset-assert 44) // (pat-length int32 :offset-assert 48) // // ;; some sort of texture remapping info // (texture-remap-table (pointer uint64) :offset-assert 52) // (texture-remap-table-len int32 :offset-assert 56) std::vector texture_remap_table; static constexpr int kNumTextureFlags = 10; u16 texture_flags[kNumTextureFlags]; // jak 2 only // // (texture-ids (pointer texture-id) :offset-assert 60) // (texture-page-count int32 :offset-assert 64) // // (unk-zero-0 basic :offset-assert 68) // // (name symbol :offset-assert 72) std::string name; // (nickname symbol :offset-assert 76) // (vis-info level-vis-info 8 :offset-assert 80) // (actors drawable-inline-array-actor :offset-assert 112) DrawableInlineArrayActor actors; // (cameras (array entity-camera) :offset-assert 116) // (nodes (inline-array bsp-node) :offset-assert 120) // // (level level :offset-assert 124) // (current-leaf-idx uint16 :offset-assert 128) // (unk-data-2 uint16 9 :offset-assert 130) // // (boxes box8s-array :offset-assert 148) // (current-bsp-back-flags uint32 :offset-assert 152) // (ambients drawable-inline-array-ambient :offset-assert 156) // (unk-data-4 float :offset-assert 160) // (unk-data-5 float :offset-assert 164) // (adgifs adgif-shader-array :offset-assert 168) // (actor-birth-order (pointer uint32) :offset-assert 172) // (split-box-indices (pointer uint16) :offset-assert 176) // (unk-data-8 uint32 55 :offset-assert 180) // jak 2 only CollideHash collide_hash; // jak 3 only std::optional hfrag; void read_from_file(const decompiler::LinkedObjectFile& file, const decompiler::DecompilerTypeSystem& dts, GameVersion version, bool only_read_texture_remap = false); std::string print(const PrintSettings& settings) const; }; } // namespace level_tools