diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 2eaba04a..7cf27a21 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -83827,7 +83827,7 @@ Address,Quality,Size,Name 0x0000007100fb6134,O,000008,_ZN14hkpGroupFilter11dummyUnusedEv 0x0000007100fb613c,O,000204,_ZNK4ksys4phys17EntityGroupFilter27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE 0x0000007100fb6208,O,000092,_ZNK4ksys4phys17EntityGroupFilter18getRuntimeTypeInfoEv -0x0000007100fb6264,O,000044,_ZN4ksys4phys17EntityGroupFilter2m2ENS0_12ContactLayerES2_ +0x0000007100fb6264,O,000044,_ZN4ksys4phys17EntityGroupFilter27shouldContactNeverBeIgnoredENS0_12ContactLayerES2_ 0x0000007100fb6290,O,000028,_ZN4ksys4phys17EntityGroupFilter23makeCollisionFilterInfoENS0_12ContactLayerENS0_9GroundHitE 0x0000007100fb62ac,O,000020,_ZN4ksys4phys17EntityGroupFilter27getCollisionFilterInfoLayerEj 0x0000007100fb62c0,O,000028,_ZN4ksys4phys17EntityGroupFilter22makeQueryCollisionMaskEjNS0_9GroundHitEb @@ -83842,18 +83842,18 @@ Address,Quality,Size,Name 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, +0x0000007100fb64d0,O,000456,_ZN4ksys4phys21EntityContactListener22collisionAddedCallbackERK17hkpCollisionEvent +0x0000007100fb6698,O,000472,_ZN4ksys4phys21EntityContactListener37setMagneMassScalingForContactIfNeededERK17hkpCollisionEventPNS0_9RigidBodyES6_ +0x0000007100fb6870,O,000320,_ZN4ksys4phys21EntityContactListener34setImpulseScalingForTerrainContactERK17hkpCollisionEventPNS0_9RigidBodyES6_ +0x0000007100fb69b0,O,000304,_ZN4ksys4phys21EntityContactListener24collisionRemovedCallbackERK17hkpCollisionEvent +0x0000007100fb6ae0,O,000492,_ZN4ksys4phys21EntityContactListener40removeViscousSurfaceModifierAndCollisionERK17hkpCollisionEventPNS0_9RigidBodyES6_ +0x0000007100fb6ccc,O,000120,_ZN4ksys4phys21EntityContactListener3m15EPNS0_9RigidBodyES3_ 0x0000007100fb6d44,O,000084,_ZN4ksys4phys21EntityContactListener27isObjectOrGroundOrNPCOrTreeERKNS0_9RigidBodyE 0x0000007100fb6d98,O,000128,_ZN4ksys4phys21EntityContactListener27isObjectOrGroundOrNPCOrTreeERK9hkpCdBody -0x0000007100fb6e18,U,000460, +0x0000007100fb6e18,O,000460,_ZN4ksys4phys21EntityContactListener24contactPointCallbackImplEjjPNS0_9RigidBodyES3_NS0_12ContactLayerES4_RK20hkpContactPointEvent 0x0000007100fb6fe4,O,000284,_ZN4ksys4phys21EntityContactListener3m11ERK20hkpContactPointEventRKNS0_23RigidBodyCollisionMasksES7_PNS0_9RigidBodyES9_ -0x0000007100fb7100,U,000344, -0x0000007100fb7258,U,002036, +0x0000007100fb7100,O,000344,_ZN4ksys4phys21EntityContactListener29setMagneMassScalingForContactERK17hkpCollisionEventPNS0_9RigidBodyES6_ +0x0000007100fb7258,m,002036,_ZN4ksys4phys21EntityContactListener27regularContactPointCallbackERK20hkpContactPointEventPNS0_9RigidBodyES6_PN4sead9SafeArrayIjLi2EEE 0x0000007100fb7a4c,O,000204,_ZNK4ksys4phys21EntityContactListener27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE 0x0000007100fb7b18,O,000092,_ZNK4ksys4phys21EntityContactListener18getRuntimeTypeInfoEv 0x0000007100fb7b74,O,000140,_ZNK4sead15RuntimeTypeInfo6DeriveIN4ksys4phys15ContactListenerEE9isDerivedEPKNS0_9InterfaceE @@ -84150,7 +84150,7 @@ Address,Quality,Size,Name 0x0000007100fc8528,O,000004,_ZN4ksys4phys24SensorSystemGroupHandlerD0Ev 0x0000007100fc852c,O,000204,_ZNK4ksys4phys17SensorGroupFilter27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE 0x0000007100fc85f8,O,000092,_ZNK4ksys4phys17SensorGroupFilter18getRuntimeTypeInfoEv -0x0000007100fc8654,O,000008,_ZN4ksys4phys11GroupFilter2m2ENS0_12ContactLayerES2_ +0x0000007100fc8654,O,000008,_ZN4ksys4phys11GroupFilter27shouldContactNeverBeIgnoredENS0_12ContactLayerES2_ 0x0000007100fc865c,O,000048,_ZN4ksys4phys17SensorGroupFilter23makeCollisionFilterInfoENS0_12ContactLayerENS0_9GroundHitE 0x0000007100fc868c,O,000024,_ZN4ksys4phys17SensorGroupFilter27getCollisionFilterInfoLayerEj 0x0000007100fc86a4,O,000008,_ZN4ksys4phys17SensorGroupFilter22makeQueryCollisionMaskEjNS0_9GroundHitEb @@ -84307,7 +84307,7 @@ Address,Quality,Size,Name 0x0000007100fce54c,O,000048,_ZN4ksys4phys15ContactListener28getContactLayerCollisionInfoEjj 0x0000007100fce57c,O,000308,_ZN4ksys4phys15ContactListener20contactPointCallbackERK20hkpContactPointEvent 0x0000007100fce6b0,O,000580,_ZN4ksys4phys15ContactListener28manifoldContactPointCallbackERK20hkpContactPointEventPNS0_9RigidBodyES6_ -0x0000007100fce8f4,O,000764,_ZN4ksys4phys15ContactListener27regularContactPointCallbackERK20hkpContactPointEventPNS0_9RigidBodyES6_PN4sead9SafeArrayINS0_16MaterialMaskDataELi2EEE +0x0000007100fce8f4,O,000764,_ZN4ksys4phys15ContactListener27regularContactPointCallbackERK20hkpContactPointEventPNS0_9RigidBodyES6_PN4sead9SafeArrayIjLi2EEE 0x0000007100fcebf0,O,001052,_ZN4ksys4phys15ContactListener22notifyContactPointInfoEPNS0_9RigidBodyES3_NS0_12ContactLayerES4_RKNS0_23RigidBodyCollisionMasksES7_RK20hkpContactPointEventb 0x0000007100fcf00c,M,000660,_ZN4ksys4phys15ContactListener27notifyLayerContactPointInfoERKNS1_24TrackedContactPointLayerEiPNS0_9RigidBodyES6_NS0_12ContactLayerES7_jjRK20hkpContactPointEvent 0x0000007100fcf2a0,O,000356,_ZN4ksys4phys15ContactListener31addLayerPairForContactPointInfoEPNS0_21LayerContactPointInfoENS0_12ContactLayerES4_b @@ -84319,7 +84319,7 @@ Address,Quality,Size,Name 0x0000007100fcf7e4,O,000112,_ZNK4ksys4phys15ContactListener27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE 0x0000007100fcf854,O,000092,_ZNK4ksys4phys15ContactListener18getRuntimeTypeInfoEv 0x0000007100fcf8b0,O,000004,_ZN4ksys4phys15ContactListener3m11ERK20hkpContactPointEventRKNS0_23RigidBodyCollisionMasksES7_PNS0_9RigidBodyES9_ -0x0000007100fcf8b4,O,000008,_ZN4ksys4phys15ContactListener3m15Ev +0x0000007100fcf8b4,O,000008,_ZN4ksys4phys15ContactListener3m15EPNS0_9RigidBodyES3_ 0x0000007100fcf8bc,O,000072,_ZN4ksys4phys21LayerContactPointInfo4makeEPN4sead4HeapEiiRKNS2_14SafeStringBaseIcEEiii 0x0000007100fcf904,O,000348,_ZN4ksys4phys21LayerContactPointInfo17registerLayerPairENS0_12ContactLayerES2_b 0x0000007100fcfa60,O,000024,_ZN4ksys4phys21LayerContactPointInfo4freeEPS1_ diff --git a/lib/hkStubs/CMakeLists.txt b/lib/hkStubs/CMakeLists.txt index c579c6ca..a1e9d62a 100644 --- a/lib/hkStubs/CMakeLists.txt +++ b/lib/hkStubs/CMakeLists.txt @@ -179,6 +179,7 @@ add_library(hkStubs OBJECT Havok/Physics2012/Dynamics/World/Memory/hkpWorldMemoryAvailableWatchDog.h Havok/Physics2012/Dynamics/World/Memory/Default/hkpDefaultWorldMemoryWatchDog.h Havok/Physics2012/Dynamics/World/Simulation/hkpSimulation.h + Havok/Physics2012/Dynamics/World/Util/hkpWorldConstraintUtil.h Havok/Physics2012/Internal/Collide/Mopp/Code/hkpMoppCode.h Havok/Physics2012/Internal/Solver/Contact/hkpSimpleContactConstraintDataInfo.h diff --git a/lib/hkStubs/Havok/Physics/Constraint/Data/hkpConstraintData.h b/lib/hkStubs/Havok/Physics/Constraint/Data/hkpConstraintData.h index 4e74f7e7..78eb7cb3 100644 --- a/lib/hkStubs/Havok/Physics/Constraint/Data/hkpConstraintData.h +++ b/lib/hkStubs/Havok/Physics/Constraint/Data/hkpConstraintData.h @@ -14,7 +14,7 @@ public: HK_DECLARE_CLASS_ALLOCATOR(hkpConstraintData) HK_DECLARE_REFLECTION() - enum ConstraintType { + enum ConstraintType : int { CONSTRAINT_TYPE_BALLANDSOCKET = 0, CONSTRAINT_TYPE_HINGE = 1, CONSTRAINT_TYPE_LIMITEDHINGE = 2, @@ -65,7 +65,7 @@ public: explicit hkpConstraintData(hkFinishLoadedObjectFlag f); HK_FORCE_INLINE ~hkpConstraintData() override; - virtual int getType() const = 0; + virtual ConstraintType getType() const = 0; virtual void getConstraintInfo(ConstraintInfo& infoOut) const = 0; virtual hkBool isValid() const = 0; diff --git a/lib/hkStubs/Havok/Physics2012/Dynamics/Constraint/Contact/hkpSimpleContactConstraintData.h b/lib/hkStubs/Havok/Physics2012/Dynamics/Constraint/Contact/hkpSimpleContactConstraintData.h index a501dc49..e4c50871 100644 --- a/lib/hkStubs/Havok/Physics2012/Dynamics/Constraint/Contact/hkpSimpleContactConstraintData.h +++ b/lib/hkStubs/Havok/Physics2012/Dynamics/Constraint/Contact/hkpSimpleContactConstraintData.h @@ -35,7 +35,7 @@ public: void getConstraintInfo(hkpConstraintData::ConstraintInfo& infoOut) const override; void getRuntimeInfo(hkBool wantRuntime, hkpConstraintData::RuntimeInfo& infoOut) const override; hkpSolverResults* getSolverResults(hkpConstraintRuntime* runtime) const override; - int getType() const override; + ConstraintType getType() const override; virtual void collisionResponseBeginCallback(const hkContactPoint& cp, struct hkpSimpleConstraintInfoInitInput& inA, diff --git a/lib/hkStubs/Havok/Physics2012/Dynamics/World/Util/hkpWorldConstraintUtil.h b/lib/hkStubs/Havok/Physics2012/Dynamics/World/Util/hkpWorldConstraintUtil.h new file mode 100644 index 00000000..6103c0ca --- /dev/null +++ b/lib/hkStubs/Havok/Physics2012/Dynamics/World/Util/hkpWorldConstraintUtil.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +struct hkConstraintInternal; + +class hkpConstraintInstance; +class hkpConstraintOwner; +class hkpEntity; +struct hkpModifierConstraintAtom; +class hkpWorld; + +class hkpWorldConstraintUtil { +public: + static void addConstraint(hkpWorld* world, hkpConstraintInstance* constraint); + + static void removeConstraint(hkpConstraintInstance* constraint); + + static hkpConstraintInstance* getConstraint(const hkpEntity* entityA, const hkpEntity* entityB); + + static void addModifier(hkpConstraintInstance* instance, hkpConstraintOwner& constraintOwner, + hkpModifierConstraintAtom* s); + + static void removeAndDeleteModifier(hkpConstraintInstance* instance, + hkpConstraintOwner& constraintOwner, + hkpConstraintAtom::AtomType type); + + static hkpModifierConstraintAtom* findModifier(hkpConstraintInstance* instance, + hkpConstraintAtom::AtomType type); + + static hkpModifierConstraintAtom* findLastModifier(hkpConstraintInstance* instance); + + static void updateFatherOfMovedAtom(hkpConstraintInstance* instance, + const hkpConstraintAtom* oldAtom, + const hkpConstraintAtom* updatedAtom, + int updatedSizeOfAtom); + + HK_FORCE_INLINE static hkpConstraintAtom* + getTerminalAtom(const hkConstraintInternal* cInternal); +}; diff --git a/src/KingSystem/Physics/CMakeLists.txt b/src/KingSystem/Physics/CMakeLists.txt index cecb70e5..557424ba 100644 --- a/src/KingSystem/Physics/CMakeLists.txt +++ b/src/KingSystem/Physics/CMakeLists.txt @@ -87,6 +87,8 @@ target_sources(uking PRIVATE RigidBody/TeraMesh/physTeraMeshRigidBodyResource.cpp RigidBody/TeraMesh/physTeraMeshRigidBodyResource.h + RigidBody/TerrainHeightField/physTerrainHeightFieldRigidBody.h + StaticCompound/physStaticCompound.cpp StaticCompound/physStaticCompound.h StaticCompound/physStaticCompoundAutogen.cpp diff --git a/src/KingSystem/Physics/RigidBody/TerrainHeightField/physTerrainHeightFieldRigidBody.h b/src/KingSystem/Physics/RigidBody/TerrainHeightField/physTerrainHeightFieldRigidBody.h new file mode 100644 index 00000000..c7b257c4 --- /dev/null +++ b/src/KingSystem/Physics/RigidBody/TerrainHeightField/physTerrainHeightFieldRigidBody.h @@ -0,0 +1,17 @@ +#pragma once + +#include "KingSystem/Physics/RigidBody/physRigidBody.h" + +namespace ksys::phys { + +class TerrainHeightFieldRigidBody : public RigidBody { + SEAD_RTTI_OVERRIDE(TerrainHeightFieldRigidBody, RigidBody) +public: + bool getD8() const { return _d8; } + +private: + void* _d0{}; + bool _d8 = false; +}; + +} // namespace ksys::phys diff --git a/src/KingSystem/Physics/RigidBody/physRigidBodyMotionEntity.h b/src/KingSystem/Physics/RigidBody/physRigidBodyMotionEntity.h index 63b5f960..a967ec2a 100644 --- a/src/KingSystem/Physics/RigidBody/physRigidBodyMotionEntity.h +++ b/src/KingSystem/Physics/RigidBody/physRigidBodyMotionEntity.h @@ -30,6 +30,12 @@ public: _200 = 1 << 9, }; + enum class ContactFlag { + _1 = 1 << 0, + _2 = 1 << 1, + _4 = 1 << 2, + }; + explicit RigidBodyMotionEntity(RigidBody* body); void setTransform(const sead::Matrix34f& mtx, bool propagate_to_linked_motions) override; @@ -122,6 +128,9 @@ public: void resetFlag(Flag flag) { mFlags.reset(flag); } void changeFlag(Flag flag, bool on) { mFlags.change(flag, on); } + auto& getContactFlags() { return mContactFlags; } + auto& getContactFlags() const { return mContactFlags; } + static void setImpulseEpsilon(float epsilon); static void setDefaultMaxImpulse(float max_impulse); @@ -152,7 +161,7 @@ private: float mRestitutionScale = 1.0f; float mMaxImpulse = -1.0f; float mColImpulseScale = 1.0f; - sead::Atomic _c4; + sead::TypedBitFlag> mContactFlags; sead::TypedBitFlag> mFlags; u32 _cc{}; sead::CriticalSection mCS; diff --git a/src/KingSystem/Physics/System/physContactListener.cpp b/src/KingSystem/Physics/System/physContactListener.cpp index 6958e891..23564f3f 100644 --- a/src/KingSystem/Physics/System/physContactListener.cpp +++ b/src/KingSystem/Physics/System/physContactListener.cpp @@ -18,18 +18,6 @@ namespace ksys::phys { -static void clearCallbackDelay(const hkpContactPointEvent& event) { - event.m_contactMgr->m_contactPointCallbackDelay = 0; -} - -static void disableContact(const hkpContactPointEvent& event) { - event.m_contactPointProperties->m_flags |= hkpContactPointProperties::CONTACT_IS_DISABLED; -} - -static bool isContactDisabled(const hkpContactPointEvent& event) { - return event.m_contactPointProperties->m_flags & hkpContactPointProperties::CONTACT_IS_DISABLED; -} - ContactListener::ContactListener(ContactMgr* mgr, ContactLayerType layer_type, int layer_count) : mMgr(mgr), mLayerType(layer_type), mLayerBase(getContactLayerBase(layer_type)), mLayerCount(layer_count) {} @@ -168,9 +156,9 @@ bool ContactListener::manifoldContactPointCallback(const hkpContactPointEvent& e return true; } -bool ContactListener::regularContactPointCallback( - const hkpContactPointEvent& event, RigidBody* body_a, RigidBody* body_b, - sead::SafeArray* out_material_masks) { +bool ContactListener::regularContactPointCallback(const hkpContactPointEvent& event, + RigidBody* body_a, RigidBody* body_b, + sead::SafeArray* out_material_masks) { auto* filter = System::instance()->getGroupFilter(mLayerType); RigidBody::CollisionMasks masks_a, masks_b; @@ -181,8 +169,8 @@ bool ContactListener::regularContactPointCallback( body_b->getCollisionMasks(&masks_b, event.getShapeKeys(1), contact_point_pos); if (out_material_masks) { - (*out_material_masks)[0] = MaterialMaskData(masks_a.material_mask); - (*out_material_masks)[1] = MaterialMaskData(masks_b.material_mask); + (*out_material_masks)[0] = masks_a.material_mask; + (*out_material_masks)[1] = masks_b.material_mask; } const auto layer_a = filter->getCollisionFilterInfoLayer(masks_a.collision_filter_info); diff --git a/src/KingSystem/Physics/System/physContactListener.h b/src/KingSystem/Physics/System/physContactListener.h index 87fc2cdd..086f4131 100644 --- a/src/KingSystem/Physics/System/physContactListener.h +++ b/src/KingSystem/Physics/System/physContactListener.h @@ -1,6 +1,9 @@ #pragma once #include +#include +#include +#include #include #include #include @@ -46,6 +49,23 @@ public: void contactPointRemovedCallback(hkpContactPointRemovedEvent& event) override {} void contactProcessCallback(hkpContactProcessEvent& event) override {} + static void clearCallbackDelay(const hkpContactPointEvent& event) { + event.m_contactMgr->m_contactPointCallbackDelay = 0; + } + + static void enableContact(const hkpContactPointEvent& event) { + event.m_contactPointProperties->m_flags &= ~hkpContactPointProperties::CONTACT_IS_DISABLED; + } + + static void disableContact(const hkpContactPointEvent& event) { + event.m_contactPointProperties->m_flags |= hkpContactPointProperties::CONTACT_IS_DISABLED; + } + + static bool isContactDisabled(const hkpContactPointEvent& event) { + return event.m_contactPointProperties->m_flags & + hkpContactPointProperties::CONTACT_IS_DISABLED; + } + protected: struct TrackedContactPointLayer { LayerContactPointInfo* info; @@ -72,12 +92,11 @@ protected: RigidBody* body_b); /// @param out_material_masks [Optional] Pass this to get the materials of the rigid bodies. - virtual bool - regularContactPointCallback(const hkpContactPointEvent& event, RigidBody* body_a, - RigidBody* body_b, - sead::SafeArray* out_material_masks); + virtual bool regularContactPointCallback(const hkpContactPointEvent& event, RigidBody* body_a, + RigidBody* body_b, + sead::SafeArray* out_material_masks); - virtual u32 m15() { return 0; } + virtual bool m15(RigidBody* body_a, RigidBody* body_b) { return false; } /// Record a contact point in the ContactPointInfo instances of the bodies (if applicable). int notifyContactPointInfo(RigidBody* body_a, RigidBody* body_b, ContactLayer layer_a, @@ -95,7 +114,7 @@ protected: return {layer1 - int(mLayerBase), layer2 - int(mLayerBase)}; } -private: +protected: ContactMgr* mMgr{}; ContactLayerType mLayerType{}; u32 mLayerBase{}; @@ -106,7 +125,8 @@ private: u32 mTrackedLayersBufferSize{}; u32 mLayerCount{}; sead::CriticalSection mCS; - u16 _90{}; + bool _90 = false; + bool _91 = false; bool mDisableContactPointInfoNotifications = false; }; diff --git a/src/KingSystem/Physics/System/physContactMgr.h b/src/KingSystem/Physics/System/physContactMgr.h index 4e4fec22..ac5b5f79 100644 --- a/src/KingSystem/Physics/System/physContactMgr.h +++ b/src/KingSystem/Physics/System/physContactMgr.h @@ -146,8 +146,8 @@ public: // 0x0000007100fb4228 void x_26(RigidBody* body_a, RigidBody* body_b); // 0x0000007100fb42f4 - void x_27(RigidBody* body_a, RigidBody* body_b, const sead::Vector3f&, const sead::Vector3f&, - u32 material_a, u32 material_b); + void x_27(RigidBody* body_a, RigidBody* body_b, const sead::Vector3f& point_position, + const sead::Vector3f& point_separating_normal, u32 material_a, u32 material_b); // 0x0000007100fb4738 void x_28(void* unk); // 0x0000007100fb49d4 diff --git a/src/KingSystem/Physics/System/physEntityContactListener.cpp b/src/KingSystem/Physics/System/physEntityContactListener.cpp index c7ae31ee..d0864888 100644 --- a/src/KingSystem/Physics/System/physEntityContactListener.cpp +++ b/src/KingSystem/Physics/System/physEntityContactListener.cpp @@ -1,9 +1,17 @@ #include "KingSystem/Physics/System/physEntityContactListener.h" #include #include +#include +#include #include +#include +#include #include +#include "KingSystem/Physics/RigidBody/TerrainHeightField/physTerrainHeightFieldRigidBody.h" #include "KingSystem/Physics/RigidBody/physRigidBody.h" +#include "KingSystem/Physics/RigidBody/physRigidBodyMotionEntity.h" +#include "KingSystem/Physics/System/physContactMgr.h" +#include "KingSystem/Physics/System/physGroupFilter.h" #include "KingSystem/Physics/System/physMaterialTable.h" #include "KingSystem/Physics/System/physSystem.h" #include "KingSystem/Physics/physConversions.h" @@ -11,6 +19,49 @@ namespace ksys::phys { +using ContactFlag = RigidBodyMotionEntity::ContactFlag; + +static bool shouldProcessEntityContact(sead::BitFlag32 ignored_layers_a, + sead::BitFlag32 ignored_layers_b, ContactLayer layer_a, + ContactLayer layer_b) { + auto* filter = System::instance()->getGroupFilter(ContactLayerType::Entity); + return filter->shouldContactNeverBeIgnored(layer_a, layer_b) || + ignored_layers_a.isOffBit(layer_b) || ignored_layers_b.isOffBit(layer_a); +} + +static bool shouldProcessEntityContact(u32 ignored_layers_a, u32 ignored_layers_b, + ContactLayer layer_a, ContactLayer layer_b) { + return shouldProcessEntityContact(sead::BitFlag32(ignored_layers_a), + sead::BitFlag32(ignored_layers_b), layer_a, layer_b); +} + +static bool shouldProcessEntityContact(const RigidBody* body_a, const RigidBody* body_b) { + const auto ignored_layers_a = body_a->getIgnoredLayers(); + const auto ignored_layers_b = body_b->getIgnoredLayers(); + + const auto layer_a = body_a->getContactLayer(); + const auto layer_b = body_b->getContactLayer(); + + return shouldProcessEntityContact(ignored_layers_a, ignored_layers_b, layer_a, layer_b); +} + +// TODO: rename +static bool hasEntityWithMotionFlag80(const hkpCollisionEvent& event) { + bool has_flag_80 = false; + auto* island = event.getSimulationIsland(); + for (int i = 0; i < island->getEntities().getSize(); ++i) { + auto* entity = getHkpEntity(*island->getEntities()[i]->getCollidable()); + if (!entity) + continue; + + bool on = getRigidBody(entity)->isEntityMotionFlag80On(); + has_flag_80 |= on; + if (on) + break; + } + return has_flag_80; +} + EntityContactListener* EntityContactListener::make(ContactMgr* mgr, sead::Heap* heap) { auto* listener = new (heap) EntityContactListener(mgr, heap); listener->init(heap); @@ -22,6 +73,60 @@ EntityContactListener::EntityContactListener(ContactMgr* mgr, sead::Heap* heap) EntityContactListener::~EntityContactListener() = default; +void EntityContactListener::collisionAddedCallback(const hkpCollisionEvent& event) { + auto* body_a = getRigidBody(event.getBody(0)); + auto* body_b = getRigidBody(event.getBody(1)); + + handleCollisionAdded(event, body_a, body_b); + + const auto ignored_layers_a = body_a->getIgnoredLayers(); + const auto ignored_layers_b = body_b->getIgnoredLayers(); + + const auto layer_a = body_a->getContactLayer(); + const auto layer_b = body_b->getContactLayer(); + + bool should_process = + shouldProcessEntityContact(ignored_layers_a, ignored_layers_b, layer_a, layer_b); + if (!should_process) { + setMagneMassScalingForContactIfNeeded(event, body_a, body_b); + setImpulseScalingForTerrainContact(event, body_a, body_b); + } + + if ((layer_a == ContactLayer::EntityWater && + body_b->getType() != RigidBody::Type::CharacterController) || + (layer_b == ContactLayer::EntityWater && + body_a->getType() != RigidBody::Type::CharacterController)) { + body_a->onCollisionAdded(); + body_b->onCollisionAdded(); + } + + if (!should_process && m15(body_a, body_b)) { + mMgr->x_26(body_a, body_b); + } +} + +void EntityContactListener::collisionRemovedCallback(const hkpCollisionEvent& event) { + auto* body_a = getRigidBody(event.getBody(0)); + auto* body_b = getRigidBody(event.getBody(1)); + + handleCollisionRemoved(event, body_a, body_b); + removeViscousSurfaceModifierAndCollision(event, body_a, body_b); + removeMassChangerModifier(event, body_a, body_b); +} + +bool EntityContactListener::m15(RigidBody* body_a, RigidBody* body_b) { + if (body_a->isEntityMotionFlag4Off() && body_b->isEntityMotionFlag4Off() && + (body_a->getMaxImpulse() >= 0 || body_b->getMaxImpulse() >= 0)) { + return true; + } + + if (body_a->isEntityMotionFlag8On() || body_b->isEntityMotionFlag8On()) { + return true; + } + + return false; +} + bool EntityContactListener::isObjectOrGroundOrNPCOrTree(const RigidBody& body) { switch (body.getContactLayer().value()) { case ContactLayer::EntityObject: @@ -45,6 +150,71 @@ bool EntityContactListener::isObjectOrGroundOrNPCOrTree(const hkpCdBody& cd_body return isObjectOrGroundOrNPCOrTree(*body); } +// TODO: rename +static bool unkLayerCheck(const RigidBody* body_a, const RigidBody* body_b, ContactLayer layer_a, + ContactLayer layer_b) { + if (layer_a.value() == ContactLayer::EntityPlayer || + layer_a.value() == ContactLayer::EntityNPC) { + switch (layer_b.value()) { + case ContactLayer::EntityObject: + case ContactLayer::EntityGroundObject: + case ContactLayer::EntityTree: + if (!body_b->hasFlag(RigidBody::Flag::_400000)) + return true; + break; + case ContactLayer::EntityPlayer: + case ContactLayer::EntityNPC: + return true; + default: + break; + } + } + + if (layer_b.value() == ContactLayer::EntityPlayer || + layer_b.value() == ContactLayer::EntityNPC) { + switch (layer_a.value()) { + case ContactLayer::EntityObject: + case ContactLayer::EntityGroundObject: + case ContactLayer::EntityTree: + if (!body_a->hasFlag(RigidBody::Flag::_400000)) + return true; + break; + default: + break; + } + } + + return false; +} + +bool EntityContactListener::contactPointCallbackImpl(u32 ignored_layers_a, u32 ignored_layers_b, + RigidBody* body_a, RigidBody* body_b, + ContactLayer layer_a, ContactLayer layer_b, + const hkpContactPointEvent& event) { + if (shouldProcessEntityContact(ignored_layers_a, ignored_layers_b, layer_a, layer_b) || + (_91 && unkLayerCheck(body_a, body_b, layer_a, layer_b))) { + disableContact(event); + + if (event.m_type == hkpContactPointEvent::TYPE_MANIFOLD && + (layer_a == ContactLayer::EntityWater || layer_b == ContactLayer::EntityWater)) { + clearCallbackDelay(event); + } + + return false; + } + + if (isContactDisabled(event)) { + auto* constraint = event.m_contactMgr->getConstraintInstance(); + if (constraint == nullptr || + constraint->getData()->getType() != hkpConstraintData::CONSTRAINT_TYPE_CONTACT || + !(constraint->getUserData() & 0x10000)) { + // Clear the contact disabled flag. + enableContact(event); + } + } + return true; +} + void EntityContactListener::m11(const hkpContactPointEvent& event, const RigidBodyCollisionMasks& masks_a, const RigidBodyCollisionMasks& masks_b, RigidBody* body_a, @@ -70,4 +240,292 @@ void EntityContactListener::m11(const hkpContactPointEvent& event, hk_point_properties->setRestitution(restitution); } +KSYS_ALWAYS_INLINE static bool needsMagneMassScaling(const hkpCollisionEvent& event, + RigidBody* body_a, RigidBody* body_b) { + if (body_a->getMotionType() != MotionType::Dynamic || + body_b->getMotionType() != MotionType::Dynamic) { + return false; + } + + if (body_a->getEntityMotionAccessor() == nullptr || + body_b->getEntityMotionAccessor() == nullptr) { + return false; + } + + if (body_a->getEntityMotionAccessor()->getContactFlags().isOff(ContactFlag::_1) && + body_b->getEntityMotionAccessor()->getContactFlags().isOff(ContactFlag::_1)) { + return false; + } + + if (!hasEntityWithMotionFlag80(event)) + return false; + + return body_a->getMagneMassScalingFactor() >= 0 && body_b->getMagneMassScalingFactor() >= 0; +} + +static void updateMotionAccessorFlagsForMagneMassScaling(RigidBody* body_a, RigidBody* body_b) { + // Set flag 1 and reset flag 2. + body_a->getEntityMotionAccessor()->getContactFlags().set(ContactFlag::_1); + body_b->getEntityMotionAccessor()->getContactFlags().set(ContactFlag::_1); + + body_a->getEntityMotionAccessor()->getContactFlags().reset(ContactFlag::_2); + body_b->getEntityMotionAccessor()->getContactFlags().reset(ContactFlag::_2); +} + +void EntityContactListener::setMagneMassScalingForContactIfNeeded(const hkpCollisionEvent& event, + RigidBody* body_a, + RigidBody* body_b) { + if (!System::instance()->getEntityContactListenerField90()) + return; + + if (!needsMagneMassScaling(event, body_a, body_b)) + return; + + updateMotionAccessorFlagsForMagneMassScaling(body_a, body_b); + setMagneMassScalingForContact(event, body_a, body_b); +} + +void EntityContactListener::setImpulseScalingForTerrainContact(const hkpCollisionEvent& event, + RigidBody* body_a, + RigidBody* body_b) { + if (body_a->getType() != RigidBody::Type::TerrainHeightField && + body_b->getType() != RigidBody::Type::TerrainHeightField) { + return; + } + + auto* body1 = body_a->getType() == RigidBody::Type::TerrainHeightField ? body_a : body_b; + auto* body2 = body1 == body_a ? body_b : body_a; + + if (body2->getType() != RigidBody::Type::CharacterController || + int(body1->getContactLayer()) != ContactLayer::EntityGround) { + return; + } + + auto* height_field_body = sead::DynamicCast(body1); + if (!height_field_body || !height_field_body->getD8()) + return; + + [[maybe_unused]] auto* constraint = event.m_contactMgr->getConstraintInstance(); + hkpResponseModifier::setImpulseScalingForContact(event.m_contactMgr, body_a->getHkBody(), + body_b->getHkBody(), + *event.getSimulationIsland(), 15.0, 25.0); +} + +static bool removeViscousSurfaceModifier(const hkpCollisionEvent& event) { + constexpr auto type = hkpConstraintAtom::TYPE_MODIFIER_VISCOUS_SURFACE; + auto* constraint = event.m_contactMgr->getConstraintInstance(); + if (!hkpWorldConstraintUtil::findModifier(constraint, type)) { + return false; + } + + auto* island = event.getSimulationIsland(); + hkpWorldConstraintUtil::removeAndDeleteModifier(constraint, *island, type); + + if (constraint && + constraint->getData()->getType() == hkpConstraintData::CONSTRAINT_TYPE_CONTACT) { + // TODO: add named constants for this flag? + constraint->m_userData &= ~1; + } + + return true; +} + +inline void EntityContactListener::removeViscousSurfaceModifierAndCollision( + const hkpCollisionEvent& event, RigidBody* body_a, RigidBody* body_b) { + if (!removeViscousSurfaceModifier(event)) + return; + + const auto update_contact_flags = [](RigidBody* body) { + if (!body->getEntityMotionAccessor()->getContactFlags().isOn(ContactFlag::_1)) { + return; + } + + if (body->isEntityMotionFlag80On()) + return; + + body->getEntityMotionAccessor()->getContactFlags().reset(ContactFlag::_1); + body->getEntityMotionAccessor()->getContactFlags().set(ContactFlag::_2); + body->getEntityMotionAccessor()->getContactFlags().reset(ContactFlag::_4); + }; + + update_contact_flags(body_a); + update_contact_flags(body_b); + body_a->onCollisionRemoved(); + body_b->onCollisionRemoved(); +} + +KSYS_ALWAYS_INLINE inline void +EntityContactListener::removeMassChangerModifier(const hkpCollisionEvent& event, RigidBody* body_a, + RigidBody* body_b) { + constexpr auto type = hkpConstraintAtom::TYPE_MODIFIER_MASS_CHANGER; + auto* constraint = event.m_contactMgr->getConstraintInstance(); + if (hkpWorldConstraintUtil::findModifier(constraint, type)) { + auto* island = event.getSimulationIsland(); + hkpWorldConstraintUtil::removeAndDeleteModifier(constraint, *island, type); + } + + const auto a_is_water_and_b_not_charctrl = [](RigidBody* a, RigidBody* b) { + return a->getContactLayer() == ContactLayer::EntityWater && + b->getType() != RigidBody::Type::CharacterController; + }; + + if (a_is_water_and_b_not_charctrl(body_a, body_b) || + a_is_water_and_b_not_charctrl(body_b, body_a)) { + body_a->onCollisionRemoved(); + body_b->onCollisionRemoved(); + } +} + +inline void EntityContactListener::setMagneMassScalingForContact(const hkpCollisionEvent& event, + RigidBody* body_a, + RigidBody* body_b) { + const auto factor_a = body_a->getMagneMassScalingFactor(); + const auto factor_b = body_b->getMagneMassScalingFactor(); + + body_a->onCollisionAdded(); + body_b->onCollisionAdded(); + + const auto mass_a = body_a->getMass(); + const auto mass_b = body_b->getMass(); + + const auto* heavier_body = (mass_a < mass_b) ? body_b : body_a; + const auto* lighter_body = (mass_a < mass_b) ? body_a : body_b; + + const auto heavier_factor = (mass_a < mass_b) ? factor_b : factor_a; + const auto lighter_factor = (mass_a < mass_b) ? factor_a : factor_b; + + const auto effective_mass1 = lighter_body->getMass() * heavier_factor; + const auto effective_mass2 = heavier_body->getMass() * lighter_factor; + + hkVector4f mass_ratio; + mass_ratio.setAll(effective_mass1 / effective_mass2); + + hkpResponseModifier::setInvMassScalingForContact(event.m_contactMgr, lighter_body->getHkBody(), + *event.getSimulationIsland(), mass_ratio); + + if (auto* constraint = event.m_contactMgr->getConstraintInstance()) { + if (constraint->getData()->getType() == hkpConstraintData::CONSTRAINT_TYPE_CONTACT) + constraint->m_userData |= 1; + } +} + +static void updateMotionFlagsAtEndOfStep(const hkpCollisionEvent& event, RigidBody* body_a, + RigidBody* body_b) { + const auto update_flags1 = [](RigidBody* a, RigidBody* b) { + if (!a->getEntityMotionAccessor()->getContactFlags().isOn(ContactFlag::_2)) + return false; + if (!b->getEntityMotionAccessor()->getContactFlags().isOn(ContactFlag::_4)) + return false; + + a->getEntityMotionAccessor()->getContactFlags().set(ContactFlag::_1); + a->getEntityMotionAccessor()->getContactFlags().reset(ContactFlag::_2); + a->getEntityMotionAccessor()->getContactFlags().set(ContactFlag::_4); + return true; + }; + + const auto update_flags2 = [](RigidBody* a, RigidBody* b) { + if (!a->getEntityMotionAccessor()->getContactFlags().isOn(ContactFlag::_2)) + return false; + if (b->isEntityMotionFlag80On()) + return false; + if (!b->getEntityMotionAccessor()->getContactFlags().isOn(ContactFlag::_1)) + return false; + + b->getEntityMotionAccessor()->getContactFlags().reset(ContactFlag::_1); + b->getEntityMotionAccessor()->getContactFlags().set(ContactFlag::_2); + return true; + }; + + const auto update_flags3 = [](RigidBody* a, RigidBody* b) { + if (!a->getEntityMotionAccessor()->getContactFlags().isOn(ContactFlag::_1)) + return false; + if (!b->getEntityMotionAccessor()->getContactFlags().isOff(ContactFlag::_1)) + return false; + + b->getEntityMotionAccessor()->getContactFlags().set(ContactFlag::_1); + b->getEntityMotionAccessor()->getContactFlags().reset(ContactFlag::_2); + return true; + }; + + const auto update_flags4 = [](RigidBody* body) { + if (!body->getEntityMotionAccessor()->getContactFlags().isOn(ContactFlag::_4)) + return false; + if (body->isEntityMotionFlag80On()) + return false; + if (body->x_105()) + return false; + + body->getEntityMotionAccessor()->getContactFlags() = ContactFlag::_1; + return true; + }; + + bool updated1 = false; + updated1 |= update_flags1(body_a, body_b); + updated1 |= update_flags1(body_b, body_a); + + if (!updated1) { + bool updated2 = false; + updated2 |= update_flags2(body_a, body_b); + updated2 |= update_flags2(body_b, body_a); + + if (updated2) { + removeViscousSurfaceModifier(event); + } else { + update_flags3(body_a, body_b); + update_flags3(body_b, body_a); + } + } + + update_flags4(body_a); + update_flags4(body_b); +} + +// NON_MATCHING: branching (body_a->getEntityMotionAccessor() call not merged) +bool EntityContactListener::regularContactPointCallback(const hkpContactPointEvent& event, + RigidBody* body_a, RigidBody* body_b, + sead::SafeArray*) { + if (event.m_type == hkpContactPointEvent::TYPE_MANIFOLD_AT_END_OF_STEP) { + auto* constraint = event.m_contactMgr->getConstraintInstance(); + + auto* modifier = hkpWorldConstraintUtil::findModifier( + constraint, hkpConstraintAtom::TYPE_MODIFIER_VISCOUS_SURFACE); + + const bool field90 = System::instance()->getEntityContactListenerField90(); + + if (modifier && constraint->getUserData() & 1) { + clearCallbackDelay(event); + + if (field90 && hasEntityWithMotionFlag80(event)) { + updateMotionFlagsAtEndOfStep(event, body_a, body_b); + } else { + body_a->getEntityMotionAccessor()->getContactFlags().makeAllZero(); + body_b->getEntityMotionAccessor()->getContactFlags().makeAllZero(); + removeViscousSurfaceModifier(event); + } + } else if (field90 && needsMagneMassScaling(event, body_a, body_b) && + !shouldProcessEntityContact(body_a, body_b)) { + updateMotionAccessorFlagsForMagneMassScaling(body_a, body_b); + setMagneMassScalingForContact(event, body_a, body_b); + } + } + + sead::SafeArray material_masks; + bool result = + ContactListener::regularContactPointCallback(event, body_a, body_b, &material_masks); + + if (event.m_contactPointProperties->m_flags & hkpContactPointProperties::CONTACT_IS_NEW && + m15(body_a, body_b)) { + sead::Vector3f position, normal; + storeToVec3(&position, event.m_contactPoint->getPosition()); + storeToVec3(&normal, event.m_contactPoint->getSeparatingNormal()); + if (body_a->isEntityMotionFlag40On() || body_b->isEntityMotionFlag40On()) { + mMgr->x_26(body_a, body_b); + } + + mMgr->x_27(body_a, body_b, position, normal, material_masks[0], material_masks[1]); + } + + return result; +} + } // namespace ksys::phys diff --git a/src/KingSystem/Physics/System/physEntityContactListener.h b/src/KingSystem/Physics/System/physEntityContactListener.h index 11445013..6eb51f4d 100644 --- a/src/KingSystem/Physics/System/physEntityContactListener.h +++ b/src/KingSystem/Physics/System/physEntityContactListener.h @@ -28,12 +28,27 @@ protected: 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; + bool regularContactPointCallback(const hkpContactPointEvent& event, RigidBody* body_a, + RigidBody* body_b, + sead::SafeArray* out_material_masks) override; - u32 m15() override; + bool m15(RigidBody* body_a, RigidBody* body_b) override; + +private: + void setMagneMassScalingForContactIfNeeded(const hkpCollisionEvent& event, RigidBody* body_a, + RigidBody* body_b); + + void setImpulseScalingForTerrainContact(const hkpCollisionEvent& event, RigidBody* body_a, + RigidBody* body_b); + + void removeViscousSurfaceModifierAndCollision(const hkpCollisionEvent& event, RigidBody* body_a, + RigidBody* body_b); + + void removeMassChangerModifier(const hkpCollisionEvent& event, RigidBody* body_a, + RigidBody* body_b); + + void setMagneMassScalingForContact(const hkpCollisionEvent& event, RigidBody* body_a, + RigidBody* body_b); }; } // namespace ksys::phys diff --git a/src/KingSystem/Physics/System/physEntityGroupFilter.cpp b/src/KingSystem/Physics/System/physEntityGroupFilter.cpp index 95317e17..646d846d 100644 --- a/src/KingSystem/Physics/System/physEntityGroupFilter.cpp +++ b/src/KingSystem/Physics/System/physEntityGroupFilter.cpp @@ -50,8 +50,8 @@ EntityGroupFilter::EntityGroupFilter(ContactLayer::ValueType first, ContactLayer EntityGroupFilter::~EntityGroupFilter() = default; void EntityGroupFilter::doInit_(sead::Heap* heap) { - // Enable all collisions by default. - mMasks.fill(0xffffffff); + // Allow any layer pairs to be ignored by a rigid body by default. + mLayersThatCanBeIgnored.fill(0xffffffff); } hkBool EntityGroupFilter::shouldHandleGroundCollision(u32 infoA, u32 infoB, diff --git a/src/KingSystem/Physics/System/physEntityGroupFilter.h b/src/KingSystem/Physics/System/physEntityGroupFilter.h index b4e3b5f7..b4c1c7d2 100644 --- a/src/KingSystem/Physics/System/physEntityGroupFilter.h +++ b/src/KingSystem/Physics/System/physEntityGroupFilter.h @@ -41,7 +41,7 @@ public: hkBool isCollisionEnabled(const hkpWorldRayCastInput& inputA, const hkpCollidable& collidableB) const override; - bool m2(ContactLayer layerA, ContactLayer layerB) override; + bool shouldContactNeverBeIgnored(ContactLayer layerA, ContactLayer layerB) override; u32 makeCollisionFilterInfo(ContactLayer layer, GroundHit ground_hit) override; ContactLayer getCollisionFilterInfoLayer(u32 info) override; u32 makeQueryCollisionMask(u32 layer_mask, GroundHit ground_hit, bool unk) override; @@ -78,7 +78,10 @@ private: int getFreeListIndex(const SystemGroupHandler* handler) override; void doInit_(sead::Heap* heap) override; - sead::SafeArray mMasks; + /// A ContactLayer::size() x ContactLayer::size() matrix such that M[i][j] indicates + /// whether contact between layers i and layers j can be ignored. + /// \see EntityContactListener and shouldContactNeverBeIgnored + sead::SafeArray mLayersThatCanBeIgnored; }; void receiverMaskEnableLayer(SensorCollisionMask* mask, ContactLayer layer); @@ -143,8 +146,9 @@ inline bool EntitySystemGroupHandler::m8() { return getIndex() > 0 && getIndex() < 0x400; } -inline bool EntityGroupFilter::m2(ContactLayer layerA, ContactLayer layerB) { - return (mMasks[layerA.value()] & (1 << layerB.value())) == 0; +inline bool EntityGroupFilter::shouldContactNeverBeIgnored(ContactLayer layerA, + ContactLayer layerB) { + return (mLayersThatCanBeIgnored[layerA.value()] & (1 << layerB.value())) == 0; } inline u32 EntityGroupFilter::makeCollisionFilterInfo(ContactLayer layer, GroundHit ground_hit) { @@ -185,7 +189,7 @@ inline const char* EntityGroupFilter::getCollisionFilterInfoLayerText(u32 info) } inline void EntityGroupFilter::setLayerCustomMask(ContactLayer layer, u32 mask) { - mMasks[layer] = mask; + mLayersThatCanBeIgnored[layer] = mask; } inline u32 EntityGroupFilter::getCollisionFilterInfoGroupHandlerIdx(u32 info) { diff --git a/src/KingSystem/Physics/System/physGroupFilter.h b/src/KingSystem/Physics/System/physGroupFilter.h index 67dd1118..d40f29bf 100644 --- a/src/KingSystem/Physics/System/physGroupFilter.h +++ b/src/KingSystem/Physics/System/physGroupFilter.h @@ -75,7 +75,11 @@ public: m_collisionLookupTable[layer - getLayerFirst()] = mask; } - virtual bool m2(ContactLayer layerA, ContactLayer layerB) { return true; } + /// Indicates whether contact between layerA and layerB should never be ignored, + /// even if the corresponding rigid bodies are configured to ignore each other's layer. + virtual bool shouldContactNeverBeIgnored(ContactLayer layerA, ContactLayer layerB) { + return true; + } /// Make a collision filter mask with the specified layer and ground hit type. virtual u32 makeCollisionFilterInfo(ContactLayer layer, GroundHit ground_hit) = 0; diff --git a/src/KingSystem/Physics/System/physSystem.h b/src/KingSystem/Physics/System/physSystem.h index 0f3766cd..3a1ebba8 100644 --- a/src/KingSystem/Physics/System/physSystem.h +++ b/src/KingSystem/Physics/System/physSystem.h @@ -77,6 +77,12 @@ public: void lockWorld(ContactLayerType type, void* a = nullptr, int b = 0, bool c = false); void unlockWorld(ContactLayerType type, void* a = nullptr, int b = 0, bool c = false); + // TODO: rename + // 0x0000007101216c60 + void setEntityContactListenerField90(bool value); + // 0x0000007101216c74 + bool getEntityContactListenerField90() const; + // 0x0000007101216cec sead::Heap* getPhysicsTempHeap(LowPriority low_priority) const; diff --git a/src/KingSystem/Physics/physConversions.h b/src/KingSystem/Physics/physConversions.h index 41f7f032..70076e12 100644 --- a/src/KingSystem/Physics/physConversions.h +++ b/src/KingSystem/Physics/physConversions.h @@ -101,16 +101,20 @@ inline u32 getShapeKeyOrMinus1(const u32* shape_key) { return shape_key ? *shape_key : u32(-1); } +inline const hkpEntity* getHkpEntity(const hkpCollidable& collidable) { + if (collidable.getType() != hkpWorldObject::BroadPhaseType::BROAD_PHASE_ENTITY) + return nullptr; + + return static_cast(collidable.getOwner()); +} + 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()); + auto* entity = getHkpEntity(collidable); if (!entity) return nullptr;