diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 25c08c6e..2eaba04a 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -83839,24 +83839,24 @@ Address,Quality,Size,Name 0x0000007100fb6368,O,000044,_ZN4ksys4phys17EntityGroupFilter23makeCollisionFilterInfoENS0_12ContactLayerENS0_9GroundHitEjj 0x0000007100fb6394,O,000028,_ZN4ksys4phys17EntityGroupFilter34setEntityLayerCollisionEnabledMaskENS0_12ContactLayerEj 0x0000007100fb63b0,O,000140,_ZNK4sead15RuntimeTypeInfo6DeriveIN4ksys4phys11GroupFilterEE9isDerivedEPKNS0_9InterfaceE -0x0000007100fb643c,U,000108,phys::makeEntityContactListener -0x0000007100fb64a8,U,000004,j_ksys::phys::ContactListener::dtor -0x0000007100fb64ac,U,000036, +0x0000007100fb643c,O,000108,_ZN4ksys4phys21EntityContactListener4makeEPNS0_10ContactMgrEPN4sead4HeapE +0x0000007100fb64a8,O,000004,_ZN4ksys4phys21EntityContactListenerD1Ev +0x0000007100fb64ac,O,000036,_ZN4ksys4phys21EntityContactListenerD0Ev 0x0000007100fb64d0,U,000456, 0x0000007100fb6698,U,000472, 0x0000007100fb6870,U,000320, 0x0000007100fb69b0,U,000304, 0x0000007100fb6ae0,U,000492, 0x0000007100fb6ccc,U,000120, -0x0000007100fb6d44,U,000084, -0x0000007100fb6d98,U,000128, +0x0000007100fb6d44,O,000084,_ZN4ksys4phys21EntityContactListener27isObjectOrGroundOrNPCOrTreeERKNS0_9RigidBodyE +0x0000007100fb6d98,O,000128,_ZN4ksys4phys21EntityContactListener27isObjectOrGroundOrNPCOrTreeERK9hkpCdBody 0x0000007100fb6e18,U,000460, -0x0000007100fb6fe4,U,000284, +0x0000007100fb6fe4,O,000284,_ZN4ksys4phys21EntityContactListener3m11ERK20hkpContactPointEventRKNS0_23RigidBodyCollisionMasksES7_PNS0_9RigidBodyES9_ 0x0000007100fb7100,U,000344, 0x0000007100fb7258,U,002036, -0x0000007100fb7a4c,U,000204, -0x0000007100fb7b18,U,000092, -0x0000007100fb7b74,U,000140, +0x0000007100fb7a4c,O,000204,_ZNK4ksys4phys21EntityContactListener27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE +0x0000007100fb7b18,O,000092,_ZNK4ksys4phys21EntityContactListener18getRuntimeTypeInfoEv +0x0000007100fb7b74,O,000140,_ZNK4sead15RuntimeTypeInfo6DeriveIN4ksys4phys15ContactListenerEE9isDerivedEPKNS0_9InterfaceE 0x0000007100fb7c00,U,000788,ActorPhysics::ctor 0x0000007100fb7f14,U,000020, 0x0000007100fb7f28,U,000004,j__ZdlPv_1006 diff --git a/src/KingSystem/Physics/CMakeLists.txt b/src/KingSystem/Physics/CMakeLists.txt index d437e5ef..cecb70e5 100644 --- a/src/KingSystem/Physics/CMakeLists.txt +++ b/src/KingSystem/Physics/CMakeLists.txt @@ -121,6 +121,8 @@ target_sources(uking PRIVATE System/physContactPointInfo.h System/physLayerContactPointInfo.cpp System/physLayerContactPointInfo.h + System/physEntityContactListener.cpp + System/physEntityContactListener.h System/physEntityGroupFilter.cpp System/physEntityGroupFilter.h System/physGroupFilter.cpp diff --git a/src/KingSystem/Physics/System/physEntityContactListener.cpp b/src/KingSystem/Physics/System/physEntityContactListener.cpp new file mode 100644 index 00000000..c7ae31ee --- /dev/null +++ b/src/KingSystem/Physics/System/physEntityContactListener.cpp @@ -0,0 +1,73 @@ +#include "KingSystem/Physics/System/physEntityContactListener.h" +#include +#include +#include +#include +#include "KingSystem/Physics/RigidBody/physRigidBody.h" +#include "KingSystem/Physics/System/physMaterialTable.h" +#include "KingSystem/Physics/System/physSystem.h" +#include "KingSystem/Physics/physConversions.h" +#include "KingSystem/Physics/physMaterialMask.h" + +namespace ksys::phys { + +EntityContactListener* EntityContactListener::make(ContactMgr* mgr, sead::Heap* heap) { + auto* listener = new (heap) EntityContactListener(mgr, heap); + listener->init(heap); + return listener; +} + +EntityContactListener::EntityContactListener(ContactMgr* mgr, sead::Heap* heap) + : ContactListener(mgr, ContactLayerType::Entity, MaxNumLayersPerType) {} + +EntityContactListener::~EntityContactListener() = default; + +bool EntityContactListener::isObjectOrGroundOrNPCOrTree(const RigidBody& body) { + switch (body.getContactLayer().value()) { + case ContactLayer::EntityObject: + case ContactLayer::EntityGroundObject: + case ContactLayer::EntityNPC: + case ContactLayer::EntityTree: + if (body.hasFlag(RigidBody::Flag::_400000)) + break; + return true; + default: + break; + } + return false; +} + +bool EntityContactListener::isObjectOrGroundOrNPCOrTree(const hkpCdBody& cd_body) { + auto* body = getRigidBody(*cd_body.getRootCollidable()); + if (!body) + return false; + + return isObjectOrGroundOrNPCOrTree(*body); +} + +void EntityContactListener::m11(const hkpContactPointEvent& event, + const RigidBodyCollisionMasks& masks_a, + const RigidBodyCollisionMasks& masks_b, RigidBody* body_a, + RigidBody* body_b) { + auto* hk_point_properties = event.m_contactPointProperties; + + const MaterialMask mat_mask_a = MaterialMaskData(masks_a.material_mask); + const MaterialMask mat_mask_b = MaterialMaskData(masks_b.material_mask); + const auto* material_table = System::instance()->getMaterialTable(); + + const auto mat_a = mat_mask_a.getMaterial(); + const auto mat_b = mat_mask_b.getMaterial(); + const auto properties = material_table->getPairProperties(mat_a, mat_b); + + const float friction = properties.friction * + sead::Mathf::min(body_a->getFrictionScale(), body_b->getFrictionScale()); + + const float restitution = + properties.restitution * sead::Mathf::min(body_a->getEffectiveRestitutionScale(), + body_b->getEffectiveRestitutionScale()); + + hk_point_properties->setFriction(friction); + hk_point_properties->setRestitution(restitution); +} + +} // namespace ksys::phys diff --git a/src/KingSystem/Physics/System/physEntityContactListener.h b/src/KingSystem/Physics/System/physEntityContactListener.h new file mode 100644 index 00000000..11445013 --- /dev/null +++ b/src/KingSystem/Physics/System/physEntityContactListener.h @@ -0,0 +1,39 @@ +#pragma once + +#include "KingSystem/Physics/System/physContactListener.h" + +class hkpCdBody; + +namespace ksys::phys { + +class EntityContactListener : public ContactListener { + SEAD_RTTI_OVERRIDE(EntityContactListener, ContactListener) +public: + static EntityContactListener* make(ContactMgr* mgr, sead::Heap* heap); + + ~EntityContactListener() override; + void collisionAddedCallback(const hkpCollisionEvent& event) override; + void collisionRemovedCallback(const hkpCollisionEvent& event) override; + + static bool isObjectOrGroundOrNPCOrTree(const RigidBody& body); + static bool isObjectOrGroundOrNPCOrTree(const hkpCdBody& cd_body); + +protected: + EntityContactListener(ContactMgr* mgr, sead::Heap* heap); + + bool contactPointCallbackImpl(u32 ignored_layers_a, u32 ignored_layers_b, RigidBody* body_a, + RigidBody* body_b, ContactLayer layer_a, ContactLayer layer_b, + const hkpContactPointEvent& event) override; + + void m11(const hkpContactPointEvent& event, const RigidBodyCollisionMasks& masks_a, + const RigidBodyCollisionMasks& masks_b, RigidBody* body_a, RigidBody* body_b) override; + + bool + regularContactPointCallback(const hkpContactPointEvent& event, RigidBody* body_a, + RigidBody* body_b, + sead::SafeArray* out_material_masks) override; + + u32 m15() override; +}; + +} // namespace ksys::phys diff --git a/src/KingSystem/Physics/System/physMaterialTable.h b/src/KingSystem/Physics/System/physMaterialTable.h index 9d94bd81..89dedf7d 100644 --- a/src/KingSystem/Physics/System/physMaterialTable.h +++ b/src/KingSystem/Physics/System/physMaterialTable.h @@ -13,6 +13,13 @@ namespace ksys::phys { class MaterialTable { public: + /// Properties for interactions between two materials. + struct MaterialPairProperties { + float friction; + float restitution; + }; + + /// Parameter object that stores an entire row of InteractionProperties. struct Values : agl::utl::IParameterObj { sead::SafeArray, Material::size()> values; }; @@ -30,6 +37,11 @@ public: void loadMaterialTable(sead::Heap* heap, agl::utl::ResParameterArchive archive); void loadSubMaterialTable(sead::Heap* heap, agl::utl::ResParameterArchive archive); + MaterialPairProperties getPairProperties(Material mat_a, Material mat_b) const { + auto& vec = mMaterialTable[mat_a].values[mat_b]; + return {vec->x, vec->y}; + } + const sead::SafeString& getSubMaterial(Material material, int submat_idx) const; const sead::SafeString& getSoundMatchingSubMaterial(Material material, int submat_idx) const; diff --git a/src/KingSystem/Physics/physConversions.h b/src/KingSystem/Physics/physConversions.h index b6dcd984..1f9aeece 100644 --- a/src/KingSystem/Physics/physConversions.h +++ b/src/KingSystem/Physics/physConversions.h @@ -1,12 +1,18 @@ #pragma once #include +#include +#include +#include +#include #include #include #include namespace ksys::phys { +class RigidBody; + inline void toVec3(sead::Vector3f* out, const hkVector4f& vec) { out->x = vec.getX(); out->y = vec.getY(); @@ -96,4 +102,20 @@ inline u32 getShapeKeyOrMinus1(const u32* shape_key) { return shape_key ? *shape_key : u32(-1); } +inline RigidBody* getRigidBody(const hkpEntity* entity) { + // This needs to be kept in sync with the RigidBody constructor! + return reinterpret_cast(entity->getUserData()); +} + +inline RigidBody* getRigidBody(const hkpCollidable& collidable) { + if (collidable.getType() != hkpWorldObject::BroadPhaseType::BROAD_PHASE_ENTITY) + return nullptr; + + auto* entity = static_cast(collidable.getOwner()); + if (!entity) + return nullptr; + + return getRigidBody(entity); +} + } // namespace ksys::phys diff --git a/src/KingSystem/Physics/physMaterialMask.h b/src/KingSystem/Physics/physMaterialMask.h index 40e73a63..f4482325 100644 --- a/src/KingSystem/Physics/physMaterialMask.h +++ b/src/KingSystem/Physics/physMaterialMask.h @@ -23,6 +23,11 @@ union MaterialMaskData { return u32(idx) < (1 << decltype(sub_material)::NumBits()); } + Material getMaterial() const { return int(material.Value()); } + int getSubMaterialIndex() const { return int(sub_material.Value()); } + FloorCode getFloorCode() const { return int(floor.Value()); } + WallCode getWallCode() const { return int(wall.Value()); } + void setFlag(bool b) { if (!b) clearFlag(); @@ -75,8 +80,11 @@ public: 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; } + + Material getMaterial() const { return mData.getMaterial(); } + int getSubMaterialIdx() const { return mData.getSubMaterialIndex(); } + FloorCode getFloorCode() const { return mData.getFloorCode(); } + WallCode getWallCode() const { return mData.getWallCode(); } const char* getMaterialName() const; const char* getSubMaterialName() const;