diff --git a/data/uking_functions.csv b/data/uking_functions.csv index e87d9928..4c96ceaa 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -84307,18 +84307,18 @@ Address,Quality,Size,Name 0x0000007100fce54c,O,000048,_ZN4ksys4phys15ContactListener28getContactLayerCollisionInfoEjj 0x0000007100fce57c,O,000308,_ZN4ksys4phys15ContactListener20contactPointCallbackERK20hkpContactPointEvent 0x0000007100fce6b0,O,000580,_ZN4ksys4phys15ContactListener28manifoldContactPointCallbackERK20hkpContactPointEventPNS0_9RigidBodyES6_ -0x0000007100fce8f4,U,000764,ksys::phys::ContactListener::m14 -0x0000007100fcebf0,U,001052,ksys::phys::ContactListener::x_2 -0x0000007100fcf00c,U,000660,ksys::phys::ContactListener::x_3 +0x0000007100fce8f4,O,000764,_ZN4ksys4phys15ContactListener27regularContactPointCallbackERK20hkpContactPointEventPNS0_9RigidBodyES6_PN4sead9SafeArrayINS0_16MaterialMaskDataELi2EEE +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 0x0000007100fcf404,O,000112,_ZN4ksys4phys15ContactListener35removeLayerPairsForContactPointInfoEPNS0_21LayerContactPointInfoE 0x0000007100fcf474,m,000576,_ZN4ksys4phys15ContactListener34removeLayerPairForContactPointInfoEPNS0_21LayerContactPointInfoENS0_12ContactLayerES4_ 0x0000007100fcf6b4,O,000124,_ZN4ksys4phys15ContactListener14trackLayerPairENS0_12ContactLayerES2_ 0x0000007100fcf730,O,000156,_ZN4ksys4phys15ContactListener17registerRigidBodyEPNS0_9RigidBodyE -0x0000007100fcf7cc,O,000024,_ZN4ksys4phys15ContactListener36characterControlContactPointCallbackEjjPNS0_9RigidBodyES3_NS0_12ContactLayerES4_RK20hkpContactPointEvent +0x0000007100fcf7cc,O,000024,_ZN4ksys4phys15ContactListener24contactPointCallbackImplEjjPNS0_9RigidBodyES3_NS0_12ContactLayerES4_RK20hkpContactPointEvent 0x0000007100fcf7e4,O,000112,_ZNK4ksys4phys15ContactListener27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE 0x0000007100fcf854,O,000092,_ZNK4ksys4phys15ContactListener18getRuntimeTypeInfoEv -0x0000007100fcf8b0,O,000004,_ZN4ksys4phys15ContactListener3m11Ev +0x0000007100fcf8b0,O,000004,_ZN4ksys4phys15ContactListener3m11ERK20hkpContactPointEventRKNS0_23RigidBodyCollisionMasksES7_PNS0_9RigidBodyES9_ 0x0000007100fcf8b4,O,000008,_ZN4ksys4phys15ContactListener3m15Ev 0x0000007100fcf8bc,O,000072,_ZN4ksys4phys21LayerContactPointInfo4makeEPN4sead4HeapEiiRKNS2_14SafeStringBaseIcEEiii 0x0000007100fcf904,O,000348,_ZN4ksys4phys21LayerContactPointInfo17registerLayerPairENS0_12ContactLayerES2_b diff --git a/lib/hkStubs/Havok/Common/Base/Types/Physics/ContactPoint/hkContactPoint.h b/lib/hkStubs/Havok/Common/Base/Types/Physics/ContactPoint/hkContactPoint.h index 87d654d0..7d6d408d 100644 --- a/lib/hkStubs/Havok/Common/Base/Types/Physics/ContactPoint/hkContactPoint.h +++ b/lib/hkStubs/Havok/Common/Base/Types/Physics/ContactPoint/hkContactPoint.h @@ -21,6 +21,7 @@ public: inline void setSeparatingNormal(const hkVector4& separatingNormal); inline void setNormalOnly(const hkVector4& normal); + /// If negative, the two bodies are penetrating. inline hkReal getDistance() const; inline hkSimdReal getDistanceSimdReal() const; inline void setDistance(hkReal d); diff --git a/src/KingSystem/Physics/CMakeLists.txt b/src/KingSystem/Physics/CMakeLists.txt index 08625137..dde16480 100644 --- a/src/KingSystem/Physics/CMakeLists.txt +++ b/src/KingSystem/Physics/CMakeLists.txt @@ -21,6 +21,7 @@ target_sources(uking PRIVATE RigidBody/physRigidBody.h RigidBody/physRigidBodyAccessor.cpp RigidBody/physRigidBodyAccessor.h + RigidBody/physRigidBodyContactEvent.h RigidBody/physRigidBodyFromResource.cpp RigidBody/physRigidBodyFromResource.h RigidBody/physRigidBodyFromShape.cpp diff --git a/src/KingSystem/Physics/RigidBody/physRigidBody.h b/src/KingSystem/Physics/RigidBody/physRigidBody.h index f8af32d9..42aad7ea 100644 --- a/src/KingSystem/Physics/RigidBody/physRigidBody.h +++ b/src/KingSystem/Physics/RigidBody/physRigidBody.h @@ -10,6 +10,7 @@ #include #include #include "KingSystem/Physics/RigidBody/physRigidBodyAccessor.h" +#include "KingSystem/Physics/RigidBody/physRigidBodyContactEvent.h" #include "KingSystem/Physics/physDefines.h" #include "KingSystem/Utils/Types.h" @@ -551,6 +552,9 @@ public: /// Get the name of this rigid body or its user. virtual const char* getName(); + RigidBodyContactCallback* getContactCallback() const { return mContactCallback; } + void setContactCallback(RigidBodyContactCallback* cb) { mContactCallback = cb; } + // Internal. void setUseSystemTimeFactor(bool use) { mFlags.change(Flag::UseSystemTimeFactor, use); } // Internal. @@ -594,7 +598,7 @@ protected: Type mType{}; MotionAccessor* mMotionAccessor = nullptr; sead::Atomic mCollisionCount; - void* _c8 = nullptr; + RigidBodyContactCallback* mContactCallback = nullptr; }; KSYS_CHECK_SIZE_NX150(RigidBody, 0xD0); diff --git a/src/KingSystem/Physics/RigidBody/physRigidBodyContactEvent.h b/src/KingSystem/Physics/RigidBody/physRigidBodyContactEvent.h new file mode 100644 index 00000000..20057597 --- /dev/null +++ b/src/KingSystem/Physics/RigidBody/physRigidBodyContactEvent.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +class hkpContactPointEvent; + +namespace ksys::phys { + +class RigidBody; +struct RigidBodyCollisionMasks; + +struct RigidBodyContactEvent { + RigidBody* body; + const RigidBodyCollisionMasks* collision_masks; + const u32* shape_keys; + const hkpContactPointEvent* event; +}; + +using RigidBodyContactCallback = sead::IDelegate1R; + +} // namespace ksys::phys diff --git a/src/KingSystem/Physics/RigidBody/physRigidBodyRequestMgr.h b/src/KingSystem/Physics/RigidBody/physRigidBodyRequestMgr.h index dda84700..1f895de2 100644 --- a/src/KingSystem/Physics/RigidBody/physRigidBodyRequestMgr.h +++ b/src/KingSystem/Physics/RigidBody/physRigidBodyRequestMgr.h @@ -84,15 +84,18 @@ private: }; KSYS_CHECK_SIZE_NX150(Unk6, 0x48); - struct PointCallback : LayerContactPointInfo::Callback { + struct PointCallback : LayerContactPointInfo::ContactCallback { explicit PointCallback(RigidBodyRequestMgr* mgr_) : mgr(mgr_) {} - void invoke(void* arg) override { mgr->someFunction2(arg); } + + bool invoke(const LayerContactPointInfo::ContactEvent& event) override { + return mgr->someFunction2(event); + } RigidBodyRequestMgr* mgr; }; // FIXME: rename, implement - void someFunction2(void* arg); + bool someFunction2(const LayerContactPointInfo::ContactEvent& event); static void someFunction(void* arg); static constexpr int NumRigidBodyBuffers = 2; diff --git a/src/KingSystem/Physics/System/physContactListener.cpp b/src/KingSystem/Physics/System/physContactListener.cpp index 370116b7..d356aff9 100644 --- a/src/KingSystem/Physics/System/physContactListener.cpp +++ b/src/KingSystem/Physics/System/physContactListener.cpp @@ -1,8 +1,8 @@ #include "KingSystem/Physics/System/physContactListener.h" #include -#include #include #include +#include #include #include #include @@ -23,6 +23,18 @@ static RigidBody* getRigidBody(hkpRigidBody* hk_body) { return reinterpret_cast(hk_body->getUserData()); } +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) {} @@ -88,8 +100,8 @@ void ContactListener::contactPointCallback(const hkpContactPointEvent& event) { static_cast(System::instance()->getGroupFilter(mLayerType)); - characterControlContactPointCallback(ignored_layers_a, ignored_layers_b, body_a, body_b, - layer_a, layer_b, event); + contactPointCallbackImpl(ignored_layers_a, ignored_layers_b, body_a, body_b, layer_a, + layer_b, event); } else if (event.m_type == hkpContactPointEvent::TYPE_MANIFOLD) { manifoldContactPointCallback(event, body_a, body_b); @@ -114,11 +126,13 @@ bool ContactListener::manifoldContactPointCallback(const hkpContactPointEvent& e const auto layer_a = filter->getCollisionFilterInfoLayer(masks_a.collision_filter_info); const auto layer_b = filter->getCollisionFilterInfoLayer(masks_b.collision_filter_info); - if (!characterControlContactPointCallback(masks_a.ignored_layers, masks_b.ignored_layers, - body_a, body_b, layer_a, layer_b, event)) { + if (!contactPointCallbackImpl(masks_a.ignored_layers, masks_b.ignored_layers, body_a, body_b, + layer_a, layer_b, event)) { return false; } + // Fire ContactPointInfo callbacks. + if (auto* info = body_a->getContactPointInfo(); info && info->getContactCallback()) { storeToVec3(&position, event.m_contactPoint->getPosition()); storeToVec3(&normal, event.m_contactPoint->getSeparatingNormal()); @@ -133,8 +147,7 @@ bool ContactListener::manifoldContactPointCallback(const hkpContactPointEvent& e info->getContactCallback()->invoke(&disable, my_event); if (disable == ContactPointInfo::ShouldDisableContact::Yes) { - event.m_contactPointProperties->m_flags |= - hkpContactPointProperties::CONTACT_IS_DISABLED; + disableContact(event); return false; } } @@ -152,8 +165,7 @@ bool ContactListener::manifoldContactPointCallback(const hkpContactPointEvent& e info->getContactCallback()->invoke(&disable, my_event); if (disable == ContactPointInfo::ShouldDisableContact::Yes) { - event.m_contactPointProperties->m_flags |= - hkpContactPointProperties::CONTACT_IS_DISABLED; + disableContact(event); return false; } } @@ -161,6 +173,199 @@ 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) { + auto* filter = System::instance()->getGroupFilter(mLayerType); + + RigidBody::CollisionMasks masks_a, masks_b; + sead::Vector3f contact_point_pos; + + storeToVec3(&contact_point_pos, event.m_contactPoint->getPosition()); + body_a->getCollisionMasks(&masks_a, event.getShapeKeys(0), contact_point_pos); + 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); + } + + const auto layer_a = filter->getCollisionFilterInfoLayer(masks_a.collision_filter_info); + const auto layer_b = filter->getCollisionFilterInfoLayer(masks_b.collision_filter_info); + const auto i = layer_a - int(mLayerBase); + const auto j = layer_b - int(mLayerBase); + + const bool result = contactPointCallbackImpl(masks_a.ignored_layers, masks_b.ignored_layers, + body_a, body_b, layer_a, layer_b, event); + if (result) + m11(event, masks_a, masks_b, body_a, body_b); + + const auto& entries = mTrackedContactPointLayers[i][j]; + + if (layer_a == ContactLayer::EntityRagdoll || layer_b == ContactLayer::EntityRagdoll) + clearCallbackDelay(event); + + // Fire rigid body callbacks. + bool callbacks_ok = true; + if (auto* callback = body_a->getContactCallback()) { + RigidBodyContactEvent my_event{body_b, &masks_b, event.getShapeKeys(1), &event}; + callbacks_ok &= callback->invoke(my_event); + } + if (auto* callback = body_b->getContactCallback()) { + RigidBodyContactEvent my_event{body_a, &masks_a, event.getShapeKeys(0), &event}; + callbacks_ok &= callback->invoke(my_event); + } + + auto notify_result = notifyContactPointInfo(body_a, body_b, layer_a, layer_b, masks_a, masks_b, + event, callbacks_ok); + + for (int idx = 0; idx < entries.size(); ++idx) { + notifyLayerContactPointInfo(*entries[idx], notify_result, body_a, body_b, layer_a, layer_b, + masks_a.material_mask, masks_b.material_mask, event); + } + + return result; +} + +int ContactListener::notifyContactPointInfo(RigidBody* body_a, RigidBody* body_b, + ContactLayer layer_a, ContactLayer layer_b, + const RigidBodyCollisionMasks& masks_a, + const RigidBodyCollisionMasks& masks_b, + const hkpContactPointEvent& event, bool callbacks_ok) { + const hkReal distance = event.m_contactPoint->getDistance(); + const bool should_notify = callbacks_ok && !mDisableContactPointInfoNotifications; + auto* info_a = body_a->getContactPointInfo(); + auto* info_b = body_b->getContactPointInfo(); + const bool contact_disabled = isContactDisabled(event); + + ContactPoint point; + point.separating_distance = distance; + + int result = 1; + + if (info_b && info_b->isLayerSubscribed(layer_a) && (info_b->get30() == 0 || distance <= 0.0) && + (info_b->get34() == 0 || !contact_disabled)) { + if (should_notify) { + point.body_a = body_b; + point.body_b = body_a; + point.material_mask_a = MaterialMaskData(masks_b.material_mask); + point.material_mask_b = MaterialMaskData(masks_a.material_mask); + point.shape_key_a = getShapeKeyOrMinus1(event.getShapeKeys(1)); + point.shape_key_b = getShapeKeyOrMinus1(event.getShapeKeys(0)); + storeToVec3(&point.position, event.m_contactPoint->getPosition()); + storeToVec3(&point.separating_normal, event.m_contactPoint->getSeparatingNormal()); + + if (mMgr->x_13(body_b->getContactPointInfo(), point, masks_a, distance < 0)) { + disableContact(event); + } + + result = 2; + } + + if (info_b->isLayerInMask2(layer_a)) + clearCallbackDelay(event); + } + + if (info_a && info_a->isLayerSubscribed(layer_b) && (info_a->get30() == 0 || distance <= 0.0) && + (info_a->get34() == 0 || !contact_disabled)) { + if (should_notify) { + point.body_a = body_a; + point.body_b = body_b; + if (result == 1) { + storeToVec3(&point.position, event.m_contactPoint->getPosition()); + storeToVec3(&point.separating_normal, event.m_contactPoint->getSeparatingNormal()); + } + point.material_mask_a = MaterialMaskData(masks_a.material_mask); + point.material_mask_b = MaterialMaskData(masks_b.material_mask); + point.shape_key_a = getShapeKeyOrMinus1(event.getShapeKeys(0)); + point.shape_key_b = getShapeKeyOrMinus1(event.getShapeKeys(1)); + point.separating_normal *= -1; + + if (mMgr->x_13(body_a->getContactPointInfo(), point, masks_b, !(distance < 0))) { + disableContact(event); + } + + result = 2; + } + + if (info_a->isLayerInMask2(layer_b)) + clearCallbackDelay(event); + } + + return result; +} + +// NON_MATCHING: branching (shape_key_b store), layer_a not being saved on the stack +void ContactListener::notifyLayerContactPointInfo(const TrackedContactPointLayer& tracked_layer, + int, RigidBody* body_a, RigidBody* body_b, + ContactLayer layer_a, ContactLayer layer_b, + u32 material_a, u32 material_b, + const hkpContactPointEvent& event) { + if (tracked_layer.do_not_delay_callback) + clearCallbackDelay(event); + + if (mDisableContactPointInfoNotifications) + return; + + const hkReal distance = event.m_contactPoint->getDistance(); + if (!(tracked_layer.info->get30() == 0 || distance <= 0.0)) + return; + + if (tracked_layer.info->get34() != 0 && isContactDisabled(event)) + return; + + ContactPoint point; + storeToVec3(&point.position, event.m_contactPoint->getPosition()); + storeToVec3(&point.separating_normal, event.m_contactPoint->getSeparatingNormal()); + + if (auto* callback = tracked_layer.info->getCallback()) { + if (tracked_layer.layer == layer_a) { + LayerContactPointInfo::ContactEvent my_event; + my_event.body_a = body_a; + my_event.body_b = body_b; + my_event.point_position = &point.position; + my_event.layer_a = layer_a; + my_event.layer_b = layer_b; + my_event.material_a = MaterialMaskData(material_a); + my_event.material_b = MaterialMaskData(material_b); + if (!callback->invoke(my_event)) + return; + } else { + LayerContactPointInfo::ContactEvent my_event; + my_event.body_a = body_b; + my_event.body_b = body_a; + my_event.point_position = &point.position; + my_event.layer_a = layer_b; + my_event.layer_b = layer_a; + my_event.material_a = MaterialMaskData(material_b); + my_event.material_b = MaterialMaskData(material_a); + if (!callback->invoke(my_event)) + return; + } + } + + if (tracked_layer.layer == layer_a) { + point.body_a = body_a; + point.body_b = body_b; + point.material_mask_a = MaterialMaskData(material_a); + point.material_mask_b = MaterialMaskData(material_b); + point.shape_key_a = getShapeKeyOrMinus1(event.getShapeKeys(0)); + point.shape_key_b = getShapeKeyOrMinus1(event.getShapeKeys(1)); + point.separating_normal *= -1; + point.separating_distance = distance < 0 ? distance : 0; + mMgr->x_15(tracked_layer.info, point, !(distance < 0)); + } else { + point.body_a = body_b; + point.body_b = body_a; + point.material_mask_a = MaterialMaskData(material_b); + point.material_mask_b = MaterialMaskData(material_a); + point.shape_key_a = getShapeKeyOrMinus1(event.getShapeKeys(1)); + point.shape_key_b = getShapeKeyOrMinus1(event.getShapeKeys(0)); + point.separating_distance = distance < 0 ? distance : 0; + mMgr->x_15(tracked_layer.info, point, distance < 0); + } +} + void ContactListener::handleCollisionAdded(const hkpCollisionEvent& event, RigidBody* body_a, RigidBody* body_b) { registerForEndOfStepContactPointCallbacks(event); @@ -243,7 +448,7 @@ void ContactListener::addLayerPairForContactPointInfo(LayerContactPointInfo* inf return; entry->info = info; entry->layer = layer1; - entry->enabled = enabled; + entry->do_not_delay_callback = enabled; }; auto& row_i = mTrackedContactPointLayers[i]; @@ -293,12 +498,11 @@ void ContactListener::registerRigidBody(RigidBody* body) { } } -bool ContactListener::characterControlContactPointCallback(u32 ignored_layers_a, - u32 ignored_layers_b, RigidBody* body_a, - RigidBody* body_b, ContactLayer layer_a, - ContactLayer layer_b, - const hkpContactPointEvent& event) { - event.m_contactPointProperties->m_flags |= hkpContactPointProperties::CONTACT_IS_DISABLED; +bool ContactListener::contactPointCallbackImpl(u32 ignored_layers_a, u32 ignored_layers_b, + RigidBody* body_a, RigidBody* body_b, + ContactLayer layer_a, ContactLayer layer_b, + const hkpContactPointEvent& event) { + disableContact(event); return false; } diff --git a/src/KingSystem/Physics/System/physContactListener.h b/src/KingSystem/Physics/System/physContactListener.h index 66c99616..db8bea43 100644 --- a/src/KingSystem/Physics/System/physContactListener.h +++ b/src/KingSystem/Physics/System/physContactListener.h @@ -16,6 +16,7 @@ class ContactLayerCollisionInfo; class ContactMgr; class LayerContactPointInfo; class RigidBody; +struct RigidBodyCollisionMasks; class ContactListener : public hkpContactListener, public sead::hostio::Node { SEAD_RTTI_BASE(ContactListener) @@ -46,12 +47,20 @@ public: void contactProcessCallback(hkpContactProcessEvent& event) override {} protected: - virtual bool characterControlContactPointCallback(u32 ignored_layers_a, u32 ignored_layers_b, - RigidBody* body_a, RigidBody* body_b, - ContactLayer layer_a, ContactLayer layer_b, - const hkpContactPointEvent& event); + struct TrackedContactPointLayer { + LayerContactPointInfo* info; + ContactLayer layer; + bool do_not_delay_callback; + }; - virtual void m11() {} + virtual 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); + + virtual void m11(const hkpContactPointEvent& event, const RigidBodyCollisionMasks& masks_a, + const RigidBodyCollisionMasks& masks_b, RigidBody* body_a, RigidBody* body_b) { + } virtual void handleCollisionAdded(const hkpCollisionEvent& event, RigidBody* body_a, RigidBody* body_b); @@ -63,23 +72,30 @@ 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; } + /// Record a contact point in the ContactPointInfo instances of the bodies (if applicable). + int notifyContactPointInfo(RigidBody* body_a, RigidBody* body_b, ContactLayer layer_a, + ContactLayer layer_b, const RigidBodyCollisionMasks& masks_a, + const RigidBodyCollisionMasks& masks_b, + const hkpContactPointEvent& event, bool callbacks_ok); + + /// Record a contact point in the specified LayerContactPointInfo (if applicable). + void notifyLayerContactPointInfo(const TrackedContactPointLayer& tracked_layer, int, + RigidBody* body_a, RigidBody* body_b, ContactLayer layer_a, + ContactLayer layer_b, u32 material_a, u32 material_b, + const hkpContactPointEvent& event); + std::pair convertToRelativeLayer(ContactLayer layer1, ContactLayer layer2) const { return {layer1 - int(mLayerBase), layer2 - int(mLayerBase)}; } private: - struct TrackedContactPointLayer { - LayerContactPointInfo* info; - ContactLayer layer; - bool enabled; - }; - ContactMgr* mMgr{}; ContactLayerType mLayerType{}; u32 mLayerBase{}; @@ -91,7 +107,7 @@ private: u32 mLayerCount{}; sead::CriticalSection mCS; u16 _90{}; - bool _92{}; + bool mDisableContactPointInfoNotifications = false; }; } // namespace ksys::phys diff --git a/src/KingSystem/Physics/System/physContactMgr.h b/src/KingSystem/Physics/System/physContactMgr.h index bd0ce4be..7a9a38f8 100644 --- a/src/KingSystem/Physics/System/physContactMgr.h +++ b/src/KingSystem/Physics/System/physContactMgr.h @@ -28,6 +28,7 @@ class CollisionInfo; class ContactLayerCollisionInfo; class ContactPointInfoBase; class RigidBody; +struct RigidBodyCollisionMasks; class ContactPointInfo; class LayerContactPointInfo; @@ -49,21 +50,21 @@ struct ContactInfoTable { sead::Buffer receivers; }; -// XXX: what exactly is this? Is this really a contact point? struct ContactPoint { enum class Flag { _1 = 1 << 0, _2 = 1 << 1, }; - void* _0; - void* _8; - sead::Vector3f _10; - sead::Vector3f _1c; - float scale; - MaterialMask material_mask1; - MaterialMask material_mask2; - void* _60; + RigidBody* body_a; + RigidBody* body_b; + sead::Vector3f position; + sead::Vector3f separating_normal; + float separating_distance; + MaterialMask material_mask_a; + MaterialMask material_mask_b; + u32 shape_key_a; + u32 shape_key_b; sead::TypedBitFlag flags; }; KSYS_CHECK_SIZE_NX150(ContactPoint, 0x70); @@ -90,6 +91,15 @@ public: void registerContactPointInfo(ContactPointInfoBase* info); void freeContactPointInfo(ContactPointInfoBase* info); + // 0x0000007100fb3284 + /// @param colliding_body_masks The collision masks of the colliding rigid bodies. + /// @returns whether contact should be disabled. + bool x_13(ContactPointInfo* info, const ContactPoint& point, + const RigidBodyCollisionMasks& colliding_body_masks, bool penetrating); + + // 0x0000007100fb3478 + void x_15(LayerContactPointInfo* info, const ContactPoint& point, bool penetrating); + // 0x0000007100fb3744 void x_17(CollisionInfo* info, RigidBody* body_a, RigidBody* body_b); // 0x0000007100fb37d4 diff --git a/src/KingSystem/Physics/System/physContactPointInfo.h b/src/KingSystem/Physics/System/physContactPointInfo.h index 763fa92c..61313ded 100644 --- a/src/KingSystem/Physics/System/physContactPointInfo.h +++ b/src/KingSystem/Physics/System/physContactPointInfo.h @@ -24,8 +24,23 @@ public: virtual ~ContactPointInfoBase() = default; virtual void freePoints() = 0; + u32 get30() const { return _30; } void set30(u32 value) { _30 = value; } + u32 get34() const { return _34; } + void set34(u32 value) { _34 = value; } + + bool isLayerSubscribed(ContactLayer layer) const { + const auto type = getContactLayerType(layer); + return mSubscribedLayers[int(type)].isOnBit(int(getContactLayerBaseRelativeValue(layer))); + } + + // TODO: rename + bool isLayerInMask2(ContactLayer layer) const { + const auto type = getContactLayerType(layer); + return mLayerMask2[int(type)].isOnBit(int(getContactLayerBaseRelativeValue(layer))); + } + bool isLinked() const { return mListNode.isLinked(); } static constexpr size_t getListNodeOffset() { return offsetof(ContactPointInfoBase, mListNode); @@ -33,7 +48,8 @@ public: protected: sead::Atomic _18; - sead::SafeArray mLayerMask; + sead::SafeArray mSubscribedLayers; + // TODO: rename sead::SafeArray mLayerMask2; u32 _2c{}; u32 _30{}; diff --git a/src/KingSystem/Physics/System/physLayerContactPointInfo.cpp b/src/KingSystem/Physics/System/physLayerContactPointInfo.cpp index 881b4d08..196f3802 100644 --- a/src/KingSystem/Physics/System/physLayerContactPointInfo.cpp +++ b/src/KingSystem/Physics/System/physLayerContactPointInfo.cpp @@ -62,27 +62,27 @@ void LayerContactPointInfo::freePoints() { void LayerContactPointInfo::Iterator::getData(sead::Vector3f* out, LayerContactPointInfo::Iterator::Mode mode) const { - const float scale = getPoint()->scale; - out->e = getPoint()->_10.e; + const float separating_distance = getPoint()->separating_distance; + out->e = getPoint()->position.e; switch (mode) { case Mode::_0: { if (getPoint()->flags.isOn(ContactPoint::Flag::_2)) return; - *out += getPoint()->_1c * -scale; + *out += getPoint()->separating_normal * -separating_distance; break; } case Mode::_1: { if (!getPoint()->flags.isOn(ContactPoint::Flag::_2)) return; - *out += getPoint()->_1c * scale; + *out += getPoint()->separating_normal * separating_distance; break; } case Mode::_2: default: { - *out += getPoint()->_1c * scale * 0.5f; + *out += getPoint()->separating_normal * separating_distance * 0.5f; break; } } diff --git a/src/KingSystem/Physics/System/physLayerContactPointInfo.h b/src/KingSystem/Physics/System/physLayerContactPointInfo.h index 0b843de2..08e9e2c2 100644 --- a/src/KingSystem/Physics/System/physLayerContactPointInfo.h +++ b/src/KingSystem/Physics/System/physLayerContactPointInfo.h @@ -6,11 +6,13 @@ #include #include "KingSystem/Physics/System/physContactPointInfo.h" #include "KingSystem/Physics/physDefines.h" +#include "KingSystem/Physics/physMaterialMask.h" #include "KingSystem/Utils/Types.h" namespace ksys::phys { struct ContactPoint; +class RigidBody; class LayerContactPointInfo : public ContactPointInfoBase { public: @@ -86,8 +88,17 @@ public: const ContactPoint* const* mPointsStart = nullptr; }; - // FIXME: figure out the types - using Callback = sead::IDelegate1; + struct ContactEvent { + RigidBody* body_a; + RigidBody* body_b; + const sead::Vector3f* point_position; + ContactLayer layer_a; + ContactLayer layer_b; + MaterialMaskData material_a; + MaterialMaskData material_b; + }; + + using ContactCallback = sead::IDelegate1R; static LayerContactPointInfo* make(sead::Heap* heap, int num, int num2, const sead::SafeString& name, int a, int b, int c); @@ -101,7 +112,8 @@ public: bool registerLayerPair(ContactLayer layer1, ContactLayer layer2, bool enabled = true); bool isPairUnknown(ContactLayer layer1, ContactLayer layer2) const; - void setCallback(Callback* callback) { mCallback = callback; } + ContactCallback* getCallback() const { return mCallback; } + void setCallback(ContactCallback* callback) { mCallback = callback; } auto begin() const { return Iterator(mPoints, _18); } auto end() const { return IteratorEnd(mPoints, _18); } @@ -113,7 +125,7 @@ private: Points mPoints{}; sead::ObjArray mLayerEntries; ContactLayerType mLayerType = ContactLayerType::Invalid; - Callback* mCallback = nullptr; + ContactCallback* mCallback = nullptr; }; KSYS_CHECK_SIZE_NX150(LayerContactPointInfo, 0x88); diff --git a/src/KingSystem/Physics/physConversions.h b/src/KingSystem/Physics/physConversions.h index 7957e16e..b6dcd984 100644 --- a/src/KingSystem/Physics/physConversions.h +++ b/src/KingSystem/Physics/physConversions.h @@ -92,4 +92,8 @@ inline void setMtxTranslation(sead::Matrix34f* mtx, const hkVector4f& translatio mtx->setTranslation(toVec3(translation)); } +inline u32 getShapeKeyOrMinus1(const u32* shape_key) { + return shape_key ? *shape_key : u32(-1); +} + } // namespace ksys::phys diff --git a/src/KingSystem/Physics/physMaterialMask.h b/src/KingSystem/Physics/physMaterialMask.h index 8baa349a..40e73a63 100644 --- a/src/KingSystem/Physics/physMaterialMask.h +++ b/src/KingSystem/Physics/physMaterialMask.h @@ -50,7 +50,7 @@ static_assert(sizeof(MaterialMaskData) == sizeof(u32)); class MaterialMask { public: MaterialMask(); - explicit MaterialMask(MaterialMaskData data); + MaterialMask(MaterialMaskData data); // NOLINT(google-explicit-constructor) MaterialMask(Material mat, FloorCode floor, WallCode wall, bool flag = false); MaterialMask(Material mat, const char* submat_name, FloorCode floor, WallCode wall, bool flag = false); @@ -66,6 +66,12 @@ public: return *this; } + MaterialMask& operator=(MaterialMaskData data) { + mData = data; + mSubMaterialNameCache = nullptr; + return *this; + } + MaterialMaskData& getData() { return mData; } const MaterialMaskData& getData() const { return mData; } u32 getRawData() const { return mData.raw; }