diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 74beccdd..2b6d9cf2 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -79484,20 +79484,20 @@ Address,Quality,Size,Name 0x0000007100e9d484,U,000092, 0x0000007100e9d4e0,U,000004,nullsub_4024 0x0000007100e9d4e4,U,000004,nullsub_4025 -0x0000007100e9d4e8,U,000028,Struct9::ctor -0x0000007100e9d504,U,000028, -0x0000007100e9d520,U,000080, -0x0000007100e9d570,U,000176, -0x0000007100e9d620,U,000032, -0x0000007100e9d640,U,000172, -0x0000007100e9d6ec,U,000048, -0x0000007100e9d71c,U,000004,nullsub_4026 -0x0000007100e9d720,U,000004,j__ZdlPv_942 -0x0000007100e9d724,U,000032, -0x0000007100e9d744,U,000092,getLastSurface -0x0000007100e9d7a0,U,000028, -0x0000007100e9d7bc,U,000048, -0x0000007100e9d7ec,U,000036, +0x0000007100e9d4e8,O,000028,_ZN4ksys4phys12MaterialMaskC1Ev +0x0000007100e9d504,O,000028,_ZN4ksys4phys12MaterialMaskC1ENS0_16MaterialMaskDataE +0x0000007100e9d520,O,000080,_ZN4ksys4phys12MaterialMaskC1ENS0_8MaterialENS0_9FloorCodeENS0_8WallCodeEb +0x0000007100e9d570,O,000176,_ZN4ksys4phys12MaterialMaskC1ENS0_8MaterialEPKcNS0_9FloorCodeENS0_8WallCodeEb +0x0000007100e9d620,O,000032,_ZN4ksys4phys12MaterialMask17getSubMaterialIdxENS0_8MaterialERKN4sead14SafeStringBaseIcEE +0x0000007100e9d640,O,000172,_ZN4ksys4phys12MaterialMaskC1ENS0_8MaterialEiNS0_9FloorCodeENS0_8WallCodeEb +0x0000007100e9d6ec,O,000048,_ZN4ksys4phys12MaterialMask18getSubMaterialNameENS0_8MaterialEi +0x0000007100e9d71c,O,000004,_ZN4ksys4phys12MaterialMaskD1Ev +0x0000007100e9d720,O,000004,_ZN4ksys4phys12MaterialMaskD0Ev +0x0000007100e9d724,O,000032,_ZNK4ksys4phys12MaterialMask15getMaterialNameEv +0x0000007100e9d744,O,000092,_ZNK4ksys4phys12MaterialMask18getSubMaterialNameEv +0x0000007100e9d7a0,O,000028,_ZN4ksys4phys12MaterialMask18getNumSubMaterialsENS0_8MaterialE +0x0000007100e9d7bc,O,000048,_ZN4ksys4phys12MaterialMask18getSubMaterialNameEii +0x0000007100e9d7ec,O,000036,_ZN4ksys4phys12MaterialMask11setMaterialENS0_8MaterialE 0x0000007100e9d810,U,000160, 0x0000007100e9d8b0,U,000536, 0x0000007100e9dac8,U,000296, diff --git a/src/KingSystem/Physics/CMakeLists.txt b/src/KingSystem/Physics/CMakeLists.txt index 7936a9f4..e2fa89d7 100644 --- a/src/KingSystem/Physics/CMakeLists.txt +++ b/src/KingSystem/Physics/CMakeLists.txt @@ -48,6 +48,8 @@ target_sources(uking PRIVATE System/physGroupFilter.h System/physInstanceSet.cpp System/physInstanceSet.h + System/physMaterialMask.cpp + System/physMaterialMask.h System/physMaterialTable.cpp System/physMaterialTable.h System/physMemSystem.cpp diff --git a/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.cpp b/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.cpp index 523f2eee..5c43e95a 100644 --- a/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.cpp +++ b/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.cpp @@ -13,32 +13,26 @@ CapsuleBody* CapsuleShape::init(sead::Heap* heap) { auto* hk_shape = new (ptr) hkpCapsuleShape(hkVector4(vertex_a.x, vertex_a.y, vertex_a.z), hkVector4(vertex_b.x, vertex_b.y, vertex_b.z), radius); - auto* body = new (heap) CapsuleBody(vertex_a, vertex_b, radius, _20, _28, _30, _34, hk_shape); + auto* body = new (heap) CapsuleBody(vertex_a, vertex_b, radius, material, sub_material, + floor_code, wall_code, hk_shape); if (_38) { - body->unk.shape_type = 1 << 23; + body->material_mask.getData().flag_23 = true; } - body->unk._10 = nullptr; - hk_shape->setUserData(body->unk.shape_type); + body->material_mask.clearSubMaterialNameCache(); + hk_shape->setUserData(body->material_mask.getRawData()); return body; } CapsuleBody* CapsuleBody::clone(sead::Heap* heap) { CapsuleShape shape; - - shape._20 = 0; - shape._28 = sead::SafeString::cEmptyString.cstr(); - shape._30 = 0; - shape._34 = 0; - shape._38 = false; shape.radius = radius; shape.vertex_a = vertex_a; shape.vertex_b = vertex_b; CapsuleBody* body = shape.init(heap); - body->unk.shape_type = unk.shape_type; - body->unk._10 = nullptr; + body->material_mask = material_mask; if (body->shape != nullptr) - body->shape->setUserData(unk.shape_type); + body->shape->setUserData(material_mask.getRawData()); return body; } diff --git a/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.h b/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.h index 3f62d705..d691c4e7 100644 --- a/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.h +++ b/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.h @@ -5,6 +5,8 @@ #include #include #include "KingSystem/Physics/RigidBody/physRigidBody.h" +#include "KingSystem/Physics/System/physDefines.h" +#include "KingSystem/Physics/System/physMaterialMask.h" class hkpShape; @@ -18,17 +20,11 @@ struct CapsuleBody { Modified = 1 << 0, }; - struct Unk { - Unk(u32 a1, const char* a2, u32 a3, u32 a4, u32 a5); - virtual ~Unk(); - - u32 shape_type = 0; - const char* _10; - }; - - CapsuleBody(const sead::Vector3f& va, const sead::Vector3f& vb, f32 r, u32 a4, const char* a5, - u32 a6, u32 a7, hkpShape* a8) - : vertex_a(va), vertex_b(vb), radius(r), unk(a4, a5, a6, a7, 0), shape(a8) {} + CapsuleBody(const sead::Vector3f& va, const sead::Vector3f& vb, f32 r, Material material, + const char* sub_material, FloorCode floor_code, WallCode wall_code, + hkpShape* shape_) + : vertex_a(va), vertex_b(vb), radius(r), + material_mask(material, sub_material, floor_code, wall_code, false), shape(shape_) {} virtual ~CapsuleBody(); virtual hkpShape* getShape(); @@ -49,7 +45,7 @@ struct CapsuleBody { sead::TypedBitFlag> flags{}; sead::Vector3f vertex_b; f32 radius; - Unk unk; + MaterialMask material_mask; hkpShape* shape; }; @@ -60,11 +56,11 @@ struct CapsuleShape { sead::Vector3f vertex_b; f32 radius; u32 _1c; - u32 _20; - const char* _28; - u32 _30; - u32 _34; - bool _38; + Material material; + const char* sub_material = sead::SafeString::cEmptyString.cstr(); + FloorCode floor_code; + WallCode wall_code; + bool _38 = false; }; class CapsuleView : public RigidBodyParamView { diff --git a/src/KingSystem/Physics/System/physDefines.h b/src/KingSystem/Physics/System/physDefines.h index 6ea54cda..4c8d045b 100644 --- a/src/KingSystem/Physics/System/physDefines.h +++ b/src/KingSystem/Physics/System/physDefines.h @@ -113,6 +113,10 @@ Misc,\ GrudgeSlow ) +constexpr bool isInvalidMaterial(Material::ValueType mat) { + return mat >= Material::size(); +} + SEAD_ENUM(GroundHit, Player,\ Animal,\ diff --git a/src/KingSystem/Physics/System/physMaterialMask.cpp b/src/KingSystem/Physics/System/physMaterialMask.cpp new file mode 100644 index 00000000..9a2072a6 --- /dev/null +++ b/src/KingSystem/Physics/System/physMaterialMask.cpp @@ -0,0 +1,80 @@ +#include "KingSystem/Physics/System/physMaterialMask.h" +#include "KingSystem/Physics/System/physMaterialTable.h" +#include "KingSystem/Physics/System/physMemSystem.h" + +namespace ksys::phys { + +MaterialMask::MaterialMask() = default; + +MaterialMask::MaterialMask(MaterialMaskData data) : mData(data) {} + +MaterialMask::MaterialMask(Material mat, FloorCode floor, WallCode wall, bool flag) { + mData.material.Init(mat); + mData.floor.Init(floor); + mData.wall.Init(wall); + mData.setFlag(flag); +} + +MaterialMask::MaterialMask(Material mat, const char* submat_name, FloorCode floor, WallCode wall, + bool flag) + : mSubMaterialNameCache(submat_name) { + auto submat_idx = getSubMaterialIdx(mat, submat_name); + if (!MaterialMaskData::isValidSubMaterialIdx(submat_idx)) + submat_idx = 0; + mData.raw = {}; + mData.material.Init(mat); + mData.sub_material.Init(submat_idx); + mData.floor.Init(floor); + mData.wall.Init(wall); + mData.setFlag(flag); +} + +MaterialMask::MaterialMask(Material mat, int submat_idx, FloorCode floor, WallCode wall, bool flag) + : mSubMaterialNameCache(getSubMaterialName(mat, submat_idx).cstr()) { + mData.raw = {}; + mData.material.Init(mat); + mData.sub_material.Init(submat_idx); + mData.floor.Init(floor); + mData.wall.Init(wall); + mData.setFlag(flag); +} + +MaterialMask::~MaterialMask() = default; + +const char* MaterialMask::getMaterialName() const { + const Material material = getMaterial(); + if (isInvalidMaterial(material.value())) + return "Incorrent"; // sic + return materialToText(material); +} + +const char* MaterialMask::getSubMaterialName() const { + if (mSubMaterialNameCache != nullptr) + return mSubMaterialNameCache; + + mSubMaterialNameCache = getSubMaterialName(getMaterial(), getSubMaterialIdx()).cstr(); + return mSubMaterialNameCache; +} + +int MaterialMask::getSubMaterialIdx(Material mat, const sead::SafeString& submat_name) { + return MemSystem::instance()->getMaterialTable()->getSubMaterialIdx(mat, submat_name); +} + +const sead::SafeString& MaterialMask::getSubMaterialName(Material mat, int submat_idx) { + return MemSystem::instance()->getMaterialTable()->getSubMaterial(mat, submat_idx); +} + +int MaterialMask::getNumSubMaterials(Material mat) { + return MemSystem::instance()->getMaterialTable()->getNumSubMaterials(mat); +} + +const sead::SafeString& MaterialMask::getSubMaterialName(int mat, int submat_idx) { + return getSubMaterialName(Material(mat), submat_idx); +} + +void MaterialMask::setMaterial(Material mat) { + mData.material = {}; + mData.material.SetUnsafe(mat); +} + +} // namespace ksys::phys diff --git a/src/KingSystem/Physics/System/physMaterialMask.h b/src/KingSystem/Physics/System/physMaterialMask.h new file mode 100644 index 00000000..de60c316 --- /dev/null +++ b/src/KingSystem/Physics/System/physMaterialMask.h @@ -0,0 +1,85 @@ +#pragma once + +#include +#include +#include "KingSystem/Physics/System/physDefines.h" +#include "KingSystem/Utils/BitField.h" + +namespace ksys::phys { + +union MaterialMaskData { + constexpr explicit MaterialMaskData(u32 raw_ = 0) : raw(raw_) {} + constexpr MaterialMaskData(const MaterialMaskData&) = default; + constexpr MaterialMaskData& operator=(const MaterialMaskData& other) { + raw = other.raw; + return *this; + } + + static constexpr bool isValidSubMaterialIdx(int idx) { + return u32(idx) < (1 << decltype(sub_material)::NumBits()); + } + + void setFlag(bool b) { + if (!b) + clearFlag(); + else + setFlag(); + } + void setFlag() { flag = 1; } + void clearFlag() { flag = 0; } + + u32 raw; + util::BitField<0, 6, u32> material; + util::BitField<6, 4, int, u32> sub_material; + util::BitField<10, 5, u32> floor; + util::BitField<15, 5, u32> wall; + // TODO: rename + util::BitField<23, 1, u32> flag_23; + // TODO: rename once we figure out what this flag is + util::BitField<31, 1, u32> flag; +}; +static_assert(sizeof(MaterialMaskData) == sizeof(u32)); + +class MaterialMask { +public: + MaterialMask(); + explicit MaterialMask(MaterialMaskData data); + MaterialMask(Material mat, FloorCode floor, WallCode wall, bool flag); + MaterialMask(Material mat, const char* submat_name, FloorCode floor, WallCode wall, bool flag); + MaterialMask(Material mat, int submat_idx, FloorCode floor, WallCode wall, bool flag); + MaterialMask(const MaterialMask& other) : mData(other.mData) {} + + // XXX: this doesn't need to be virtual. + virtual ~MaterialMask(); + + MaterialMask& operator=(const MaterialMask& other) { + mData = other.mData; + mSubMaterialNameCache = nullptr; + return *this; + } + + MaterialMaskData& getData() { return mData; } + const MaterialMaskData& getData() const { return mData; } + u32 getRawData() const { return mData.raw; } + Material getMaterial() const { return Material::ValueType(mData.material.Value()); } + int getSubMaterialIdx() const { return mData.sub_material; } + + const char* getMaterialName() const; + const char* getSubMaterialName() const; + + void setMaterial(Material mat); + void clearSubMaterialNameCache() { mSubMaterialNameCache = nullptr; } + + static int getSubMaterialIdx(Material mat, const sead::SafeString& submat_name); + static const sead::SafeString& getSubMaterialName(Material mat, int submat_idx); + static int getNumSubMaterials(Material mat); + static const sead::SafeString& getSubMaterialName(int mat, int submat_idx); + +private: + MaterialMaskData mData{}; + /// Fetching the name of a sub-material from the MaterialTable is an expensive operation, + /// so it is only done once and the result is cached. + mutable const char* mSubMaterialNameCache{}; +}; + +} // namespace ksys::phys diff --git a/src/KingSystem/Physics/System/physMemSystem.h b/src/KingSystem/Physics/System/physMemSystem.h index 4b2d3dca..cdaaba5e 100644 --- a/src/KingSystem/Physics/System/physMemSystem.h +++ b/src/KingSystem/Physics/System/physMemSystem.h @@ -9,9 +9,11 @@ namespace ksys::phys { class ContactMgr; class GroupFilter; +class MaterialTable; class RigidBody; class RigidContactPoints; class RigidContactPointsEx; +class SystemData; class SystemGroupHandler; // FIXME: obviously incomplete. Also this should be moved to its own header @@ -28,6 +30,8 @@ public: GroupFilter* getGroupFilter(ContactLayerType type) const; ContactMgr* getContactMgr() const { return mContactMgr; } RigidBodyRequestMgr* getRigidBodyRequestMgr() const { return mRigidBodyRequestMgr; } + SystemData* getSystemData() const { return mSystemData; } + MaterialTable* getMaterialTable() const { return mMaterialTable; } RigidContactPoints* allocContactPoints(sead::Heap* heap, int num, const sead::SafeString& name, int a, int b, int c) const; @@ -48,7 +52,11 @@ private: void* _150; void* _158; RigidBodyRequestMgr* mRigidBodyRequestMgr; - u8 _168[0x480 - 0x168]; + void* _168; + void* mRigidBodyDividedMeshShapeMgr; + SystemData* mSystemData; + MaterialTable* mMaterialTable; + u8 _188[0x480 - 0x188]; }; KSYS_CHECK_SIZE_NX150(MemSystem, 0x480); diff --git a/src/KingSystem/Utils/BitField.h b/src/KingSystem/Utils/BitField.h index 6b00b7df..4e28e675 100644 --- a/src/KingSystem/Utils/BitField.h +++ b/src/KingSystem/Utils/BitField.h @@ -116,6 +116,10 @@ struct BitField { // so that we can use this within unions constexpr BitField() = default; + // We declare a user-defined copy assignment operator, so the default copy constructor + // must be defaulted explicitly to avoid a deprecation warning. + constexpr BitField(const BitField&) = default; + // This constructor might be considered ambiguous: // Would it initialize the storage or just the bitfield? // Hence, delete it. Use the assignment operator to set bitfield values! @@ -132,6 +136,11 @@ struct BitField { storage = (storage & ~GetMask()) | (static_cast(val) << position); } + /// @warning Same as SetUnsafe, but assumes this bitfield's bits are zero. + /// This is intended to be called only once to efficiently initialise a bitfield, + /// and will break very badly if called more than once. Using Set() is preferred. + inline constexpr void Init(T val) { storage |= static_cast(val) << position; } + inline constexpr BitField& operator=(const BitField& other) { Set(other.Value()); return *this;