diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 4c96ceaa..bdf0e409 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -83747,8 +83747,8 @@ Address,Quality,Size,Name 0x0000007100fb2474,O,000116,_ZN4ksys4phys10ContactMgr20freeContactPointPoolEv 0x0000007100fb24e8,O,000316,_ZN4ksys4phys10ContactMgr20loadContactInfoTableEPN4sead4HeapEN3agl3utl19ResParameterArchiveENS0_16ContactLayerTypeE 0x0000007100fb2624,O,000688,_ZN4ksys4phys10ContactMgr22doLoadContactInfoTableEN3agl3utl19ResParameterArchiveENS0_16ContactLayerTypeEb -0x0000007100fb28d4,O,000136,_ZN4ksys4phys10ContactMgr18allocContactPointsEPN4sead4HeapEiRKNS2_14SafeStringBaseIcEEiii -0x0000007100fb295c,O,000220,_ZN4ksys4phys10ContactMgr20allocContactPointsExEPN4sead4HeapEiiRKNS2_14SafeStringBaseIcEEiii +0x0000007100fb28d4,O,000136,_ZN4ksys4phys10ContactMgr20makeContactPointInfoEPN4sead4HeapEiRKNS2_14SafeStringBaseIcEEiii +0x0000007100fb295c,O,000220,_ZN4ksys4phys10ContactMgr25makeLayerContactPointInfoEPN4sead4HeapEiiRKNS2_14SafeStringBaseIcEEiii 0x0000007100fb2a38,O,000100,_ZN4ksys4phys10ContactMgr24registerContactPointInfoEPNS0_20ContactPointInfoBaseE 0x0000007100fb2a9c,U,000056,phys::ContactInfoTable::allocCollisionInfo 0x0000007100fb2ad4,U,000156,phys::ContactInfoTable::x_2 @@ -83761,14 +83761,14 @@ Address,Quality,Size,Name 0x0000007100fb2fa4,U,000152,phys::ContactInfoTable::x_10 0x0000007100fb303c,U,000380,phys::ContactInfoTable::x_11 0x0000007100fb31b8,U,000204,phys::ContactInfoTable::x_12 -0x0000007100fb3284,U,000500,phys::ContactInfoTable::x_13 -0x0000007100fb3478,U,000340,phys::ContactInfoTable::x_15 +0x0000007100fb3284,O,000500,_ZN4ksys4phys10ContactMgr20registerContactPointEPNS0_16ContactPointInfoERKNS0_12ContactPointERKNS0_23RigidBodyCollisionMasksEb +0x0000007100fb3478,O,000340,_ZN4ksys4phys10ContactMgr20registerContactPointEPNS0_21LayerContactPointInfoERKNS0_12ContactPointEb 0x0000007100fb35cc,U,000376,phys::ContactInfoTable::x_16 -0x0000007100fb3744,U,000144,phys::ContactInfoTable::x_17 -0x0000007100fb37d4,U,000128,phys::ContactInfoTable::x_18 -0x0000007100fb3854,U,000228,phys::ContactInfoTable::x_19 -0x0000007100fb3938,U,000244,phys::ContactInfoTable::x_20 -0x0000007100fb3a2c,U,000292,phys::ContactInfoTable::x_21 +0x0000007100fb3744,O,000144,_ZN4ksys4phys10ContactMgr17registerCollisionEPNS0_13CollisionInfoEPNS0_9RigidBodyES5_ +0x0000007100fb37d4,O,000128,_ZN4ksys4phys10ContactMgr17registerCollisionEPNS0_25ContactLayerCollisionInfoEPNS0_9RigidBodyES5_ +0x0000007100fb3854,O,000228,_ZN4ksys4phys10ContactMgr19unregisterCollisionEPNS0_13CollisionInfoEPNS0_9RigidBodyES5_ +0x0000007100fb3938,O,000244,_ZN4ksys4phys10ContactMgr19unregisterCollisionEPNS0_25ContactLayerCollisionInfoEPNS0_9RigidBodyES5_ +0x0000007100fb3a2c,O,000292,_ZN4ksys4phys10ContactMgr27unregisterCollisionWithBodyEPNS0_25ContactLayerCollisionInfoEPNS0_9RigidBodyE 0x0000007100fb3b50,U,000100,phys::ContactInfoTable::x_22 0x0000007100fb3bb4,U,000652,phys::ContactInfoTable::getLayerMaskForContactPoints 0x0000007100fb3e40,U,000644,phys::ContactInfoTable::getLayerMaskForCollisionInfoStuff diff --git a/src/KingSystem/Physics/System/physCollisionInfo.cpp b/src/KingSystem/Physics/System/physCollisionInfo.cpp index ef8f4360..837c6386 100644 --- a/src/KingSystem/Physics/System/physCollisionInfo.cpp +++ b/src/KingSystem/Physics/System/physCollisionInfo.cpp @@ -12,12 +12,11 @@ void CollisionInfo::free(CollisionInfo* info) { } CollisionInfo::CollisionInfo(const sead::SafeString& name) : sead::INamable(name) { - // FIXME: figure out what this is - mList.initOffset(0x10); + mCollidingBodies.initOffset(CollidingBodies::getListNodeOffset()); } CollisionInfo::~CollisionInfo() { - mList.clear(); + mCollidingBodies.clear(); } } // namespace ksys::phys diff --git a/src/KingSystem/Physics/System/physCollisionInfo.h b/src/KingSystem/Physics/System/physCollisionInfo.h index dd2e3265..98c36cee 100644 --- a/src/KingSystem/Physics/System/physCollisionInfo.h +++ b/src/KingSystem/Physics/System/physCollisionInfo.h @@ -10,6 +10,16 @@ namespace ksys::phys { +class RigidBody; + +struct CollidingBodies { + RigidBody* body_a; + RigidBody* body_b; + sead::ListNode list_node; + + static constexpr size_t getListNodeOffset() { return offsetof(CollidingBodies, list_node); } +}; + class CollisionInfoBase { public: CollisionInfoBase() = default; @@ -38,12 +48,14 @@ public: explicit CollisionInfo(const sead::SafeString& name); ~CollisionInfo() override; + sead::OffsetList& getCollidingBodies() { return mCollidingBodies; } + const sead::OffsetList& getCollidingBodies() const { return mCollidingBodies; } + bool isLinked() const { return mListNode.isLinked(); } static constexpr size_t getListNodeOffset() { return offsetof(CollisionInfo, mListNode); } private: - // FIXME: type - sead::OffsetList mList; + sead::OffsetList mCollidingBodies; sead::ListNode mListNode; }; diff --git a/src/KingSystem/Physics/System/physContactLayerCollisionInfo.cpp b/src/KingSystem/Physics/System/physContactLayerCollisionInfo.cpp index 72d5ffb1..baabae98 100644 --- a/src/KingSystem/Physics/System/physContactLayerCollisionInfo.cpp +++ b/src/KingSystem/Physics/System/physContactLayerCollisionInfo.cpp @@ -3,8 +3,7 @@ namespace ksys::phys { ContactLayerCollisionInfo::ContactLayerCollisionInfo(ContactLayer layer) : mLayer(layer) { - // FIXME: figure out what this is - mList.initOffset(0x10); + mCollidingBodies.initOffset(CollidingBodies::getListNodeOffset()); } ContactLayerCollisionInfo::~ContactLayerCollisionInfo() = default; diff --git a/src/KingSystem/Physics/System/physContactLayerCollisionInfo.h b/src/KingSystem/Physics/System/physContactLayerCollisionInfo.h index d2819e85..798dd5f5 100644 --- a/src/KingSystem/Physics/System/physContactLayerCollisionInfo.h +++ b/src/KingSystem/Physics/System/physContactLayerCollisionInfo.h @@ -14,13 +14,12 @@ public: ContactLayer getLayer() const { return mLayer; } - auto& getList() { return mList; } - const auto& getList() const { return mList; } + sead::OffsetList& getCollidingBodies() { return mCollidingBodies; } + const sead::OffsetList& getCollidingBodies() const { return mCollidingBodies; } private: ContactLayer mLayer; - // FIXME: type - sead::OffsetList mList; + sead::OffsetList mCollidingBodies; }; } // namespace ksys::phys diff --git a/src/KingSystem/Physics/System/physContactListener.cpp b/src/KingSystem/Physics/System/physContactListener.cpp index d356aff9..9195b2c2 100644 --- a/src/KingSystem/Physics/System/physContactListener.cpp +++ b/src/KingSystem/Physics/System/physContactListener.cpp @@ -255,7 +255,8 @@ int ContactListener::notifyContactPointInfo(RigidBody* body_a, RigidBody* body_b 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)) { + if (mMgr->registerContactPoint(body_b->getContactPointInfo(), point, masks_a, + distance < 0)) { disableContact(event); } @@ -281,7 +282,8 @@ int ContactListener::notifyContactPointInfo(RigidBody* body_a, RigidBody* body_b point.shape_key_b = getShapeKeyOrMinus1(event.getShapeKeys(1)); point.separating_normal *= -1; - if (mMgr->x_13(body_a->getContactPointInfo(), point, masks_b, !(distance < 0))) { + if (mMgr->registerContactPoint(body_a->getContactPointInfo(), point, masks_b, + !(distance < 0))) { disableContact(event); } @@ -353,7 +355,7 @@ void ContactListener::notifyLayerContactPointInfo(const TrackedContactPointLayer 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)); + mMgr->registerContactPoint(tracked_layer.info, point, !(distance < 0)); } else { point.body_a = body_b; point.body_b = body_a; @@ -362,7 +364,7 @@ void ContactListener::notifyLayerContactPointInfo(const TrackedContactPointLayer 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); + mMgr->registerContactPoint(tracked_layer.info, point, distance < 0); } } @@ -374,22 +376,22 @@ void ContactListener::handleCollisionAdded(const hkpCollisionEvent& event, Rigid const auto layer_b = body_b->getContactLayer(); if (body_a->getCollisionInfo() && body_a->getCollisionInfo()->isLayerEnabled(layer_b)) - mMgr->x_17(body_a->getCollisionInfo(), body_a, body_b); + mMgr->registerCollision(body_a->getCollisionInfo(), body_a, body_b); if (body_b->getCollisionInfo() && body_b->getCollisionInfo()->isLayerEnabled(layer_a)) - mMgr->x_17(body_b->getCollisionInfo(), body_b, body_a); + mMgr->registerCollision(body_b->getCollisionInfo(), body_b, body_a); const auto i = int(layer_a - mLayerBase); const auto j = int(layer_b - mLayerBase); if (areContactsTrackedForLayerPair(i, j)) { - auto* info = getContactLayerCollisionInfo(i, j); + auto* layer_col_info = getContactLayerCollisionInfo(i, j); if (body_a->isFlag8Set() && body_b->isFlag8Set()) { const auto layer_a_ = int(layer_a); - const auto tracked_layer = info->getLayer(); + const auto tracked_layer = layer_col_info->getLayer(); const bool body_a_first = layer_a_ == tracked_layer; auto* body1 = body_a_first ? body_a : body_b; auto* body2 = body_a_first ? body_b : body_a; - mMgr->x_18(info, body1, body2); + mMgr->registerCollision(layer_col_info, body1, body2); } } } @@ -402,21 +404,21 @@ void ContactListener::handleCollisionRemoved(const hkpCollisionEvent& event, Rig const auto layer_b = body_b->getContactLayer(); if (auto* info = body_a->getCollisionInfo()) - mMgr->x_19(info, body_a, body_b); + mMgr->unregisterCollision(info, body_a, body_b); if (auto* info = body_b->getCollisionInfo()) - mMgr->x_19(info, body_b, body_a); + mMgr->unregisterCollision(info, body_b, body_a); const auto i = int(layer_a - mLayerBase); const auto j = int(layer_b - mLayerBase); auto* info = getContactLayerCollisionInfo(i, j); - if (!info->getList().isEmpty()) { + if (!info->getCollidingBodies().isEmpty()) { const auto layer_a_ = int(layer_a); const auto tracked_layer = info->getLayer(); const bool body_a_first = layer_a_ == tracked_layer; auto* body1 = body_a_first ? body_a : body_b; auto* body2 = body_a_first ? body_b : body_a; - mMgr->x_20(info, body1, body2); + mMgr->unregisterCollision(info, body1, body2); } } @@ -494,7 +496,7 @@ void ContactListener::registerRigidBody(RigidBody* body) { auto& column = mCollisionInfoPerLayerPair[int(rlayer)]; for (u32 i = 0; i < mLayerCount; ++i) { ContactLayerCollisionInfo* info = column[int(i)]; - mMgr->x_21(info, body); + mMgr->unregisterCollisionWithBody(info, body); } } diff --git a/src/KingSystem/Physics/System/physContactMgr.cpp b/src/KingSystem/Physics/System/physContactMgr.cpp index 02b76086..8ec54e3c 100644 --- a/src/KingSystem/Physics/System/physContactMgr.cpp +++ b/src/KingSystem/Physics/System/physContactMgr.cpp @@ -1,19 +1,22 @@ #include "KingSystem/Physics/System/physContactMgr.h" #include +#include "KingSystem/Physics/System/physCollisionInfo.h" +#include "KingSystem/Physics/System/physContactLayerCollisionInfo.h" #include "KingSystem/Physics/System/physContactPointInfo.h" #include "KingSystem/Physics/System/physEntityGroupFilter.h" #include "KingSystem/Physics/System/physGroupFilter.h" #include "KingSystem/Physics/System/physLayerContactPointInfo.h" #include "KingSystem/Physics/System/physSystem.h" +#include "KingSystem/Utils/Debug.h" namespace ksys::phys { ContactMgr::ContactMgr() { - mRigidContactPoints.initOffset(ContactPointInfo::getListNodeOffset()); + mContactPointInfoInstances.initOffset(ContactPointInfo::getListNodeOffset()); // FIXME: figure out what these offsets are mList2.initOffset(0x78); mList3.initOffset(0x40); - mList0.initOffset(0x10); + mCollidingBodiesFreeList.initOffset(CollidingBodies::getListNodeOffset()); mList4.initOffset(0x48); mList5.initOffset(0x48); } @@ -76,42 +79,172 @@ void ContactMgr::doLoadContactInfoTable(agl::utl::ResParameterArchive archive, table.param_io.applyResParameterArchive(archive); } -ContactPointInfo* ContactMgr::allocContactPoints(sead::Heap* heap, int num, - const sead::SafeString& name, int a, int b, - int c) { - auto* points = new (heap) ContactPointInfo(name, a, b, c); - points->allocPoints(heap, num); - return points; +ContactPointInfo* ContactMgr::makeContactPointInfo(sead::Heap* heap, int num, + const sead::SafeString& name, int a, int b, + int c) { + auto* info = new (heap) ContactPointInfo(name, a, b, c); + info->allocPoints(heap, num); + return info; } -LayerContactPointInfo* ContactMgr::allocContactPointsEx(sead::Heap* heap, int num, int num2, - const sead::SafeString& name, int a, int b, - int c) { - auto* points = new (heap) LayerContactPointInfo(name, a, b, c); - points->allocPoints(heap, num, num2); - registerContactPointInfo(points); - return points; +LayerContactPointInfo* ContactMgr::makeLayerContactPointInfo(sead::Heap* heap, int num, int num2, + const sead::SafeString& name, int a, + int b, int c) { + auto* info = new (heap) LayerContactPointInfo(name, a, b, c); + info->allocPoints(heap, num, num2); + registerContactPointInfo(info); + return info; } void ContactMgr::registerContactPointInfo(ContactPointInfoBase* info) { - auto lock = sead::makeScopedLock(mMutex1); + auto lock = sead::makeScopedLock(mContactPointInfoMutex); if (!info->isLinked()) - mRigidContactPoints.pushBack(info); + mContactPointInfoInstances.pushBack(info); +} + +void ContactMgr::unregisterContactPointInfo(ContactPointInfoBase* info) { + auto lock = sead::makeScopedLock(mContactPointInfoMutex); + if (info->isLinked()) + mContactPointInfoInstances.erase(info); } void ContactMgr::freeContactPointInfo(ContactPointInfoBase* info) { if (!info) return; - { - auto lock = sead::makeScopedLock(mMutex1); - if (info->isLinked()) - mRigidContactPoints.erase(info); - } + unregisterContactPointInfo(info); info->freePoints(); delete info; } +int ContactMgr::allocateContactPoint() { + if (mContactPointIndex >= mContactPointPool.size() - 1) { + util::PrintDebugFmt("contact point pool exhausted (current index: %d)", + mContactPointIndex.load()); + return -1; + } + return mContactPointIndex.increment(); +} + +bool ContactMgr::registerContactPoint(ContactPointInfo* info, const ContactPoint& point, + const RigidBodyCollisionMasks& colliding_body_masks, + bool penetrating) { + if (!info->isLinked()) + return false; + + auto disable_contact = ContactPointInfo::ShouldDisableContact::No; + + if (auto* callback = info->getContactCallback()) { + ContactPointInfo::Event event; + event.body = point.body_b; + event.position = &point.position; + event.separating_normal = &point.separating_normal; + event.collision_masks = &colliding_body_masks; + if (!callback->invoke(&disable_contact, event)) + return disable_contact == ContactPointInfo::ShouldDisableContact::Yes; + } + + int pool_index = allocateContactPoint(); + if (pool_index != -1) { + auto& point_in_pool = mContactPointPool[pool_index]; + point_in_pool = point; + + if (info->mContactPointIndex < info->mPoints.size() || info->_2c >= 2) { + int index = info->mContactPointIndex.increment(); + info->mPoints[index] = &point_in_pool; + info->mPoints[index]->flags.makeAllZero(); + info->mPoints[index]->flags.change(ContactPoint::Flag::Penetrating, penetrating); + } + } + + return disable_contact == ContactPointInfo::ShouldDisableContact::Yes; +} + +void ContactMgr::registerContactPoint(LayerContactPointInfo* info, const ContactPoint& point, + bool penetrating) { + int pool_index = allocateContactPoint(); + if (pool_index == -1) + return; + + auto& point_in_pool = mContactPointPool[pool_index]; + point_in_pool = point; + + if (info->mContactPointIndex < info->mPoints.size()) { + int index = info->mContactPointIndex.increment(); + info->mPoints[index] = &point_in_pool; + info->mPoints[index]->flags.makeAllZero(); + info->mPoints[index]->flags.change(ContactPoint::Flag::Penetrating, penetrating); + } +} + +void ContactMgr::registerCollision(CollisionInfo* info, RigidBody* body_a, RigidBody* body_b) { + auto lock = sead::makeScopedLock(mCollidingBodiesMutex); + if (!info->isLinked()) + return; + + auto* entry = mCollidingBodiesFreeList.popFront(); + if (entry) { + entry->body_a = body_a; + entry->body_b = body_b; + info->getCollidingBodies().pushBack(entry); + } +} + +void ContactMgr::registerCollision(ContactLayerCollisionInfo* info, RigidBody* body_a, + RigidBody* body_b) { + auto lock = sead::makeScopedLock(mCollidingBodiesMutex); + + auto* entry = mCollidingBodiesFreeList.popFront(); + if (entry) { + entry->body_a = body_a; + entry->body_b = body_b; + info->getCollidingBodies().pushBack(entry); + } +} + +void ContactMgr::unregisterCollision(CollisionInfo* info, RigidBody* body_a, RigidBody* body_b) { + auto lock = sead::makeScopedLock(mCollidingBodiesMutex); + auto info_lock = sead::makeScopedLock(*info); + + for (auto& entry : info->getCollidingBodies()) { + if (entry.body_a == body_a && entry.body_b == body_b) { + info->getCollidingBodies().erase(&entry); + mCollidingBodiesFreeList.pushBack(&entry); + break; + } + } +} + +void ContactMgr::unregisterCollision(ContactLayerCollisionInfo* info, RigidBody* body_a, + RigidBody* body_b) { + auto lock = sead::makeScopedLock(mCollidingBodiesMutex); + auto info_lock = sead::makeScopedLock(*info); + + for (auto& entry : info->getCollidingBodies()) { + if (entry.body_a == body_a && entry.body_b == body_b) { + info->getCollidingBodies().erase(&entry); + freeCollidingBodiesEntry(&entry); + break; + } + } +} + +void ContactMgr::unregisterCollisionWithBody(ContactLayerCollisionInfo* info, RigidBody* body) { + auto lock = sead::makeScopedLock(mCollidingBodiesMutex); + auto info_lock = sead::makeScopedLock(*info); + + auto body_layer = body->getContactLayer(); + + for (auto& entry : info->getCollidingBodies().robustRange()) { + auto* body_a = entry.body_a; + auto* body_b = int(body_a->getContactLayer()) == body_layer ? body_a : entry.body_b; + if (body_b == body) { + info->getCollidingBodies().erase(&entry); + freeCollidingBodiesEntry(&entry); + } + } +} + bool ContactMgr::getSensorLayerMask(SensorCollisionMask* mask, const sead::SafeString& receiver_type) const { const auto& receivers = mContactInfoTables[int(ContactLayerType::Sensor)].receivers; diff --git a/src/KingSystem/Physics/System/physContactMgr.h b/src/KingSystem/Physics/System/physContactMgr.h index 7a9a38f8..b0dce486 100644 --- a/src/KingSystem/Physics/System/physContactMgr.h +++ b/src/KingSystem/Physics/System/physContactMgr.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include "KingSystem/Physics/physDefines.h" @@ -24,6 +25,7 @@ namespace ksys::phys { enum class IsIndoorStage; +struct CollidingBodies; class CollisionInfo; class ContactLayerCollisionInfo; class ContactPointInfoBase; @@ -53,7 +55,7 @@ struct ContactInfoTable { struct ContactPoint { enum class Flag { _1 = 1 << 0, - _2 = 1 << 1, + Penetrating = 1 << 1, }; RigidBody* body_a; @@ -84,51 +86,61 @@ public: bool getSensorLayerMask(SensorCollisionMask* mask, const sead::SafeString& receiver_type) const; - ContactPointInfo* allocContactPoints(sead::Heap* heap, int num, const sead::SafeString& name, - int a, int b, int c); - LayerContactPointInfo* allocContactPointsEx(sead::Heap* heap, int num, int num2, - const sead::SafeString& name, int a, int b, int c); + ContactPointInfo* makeContactPointInfo(sead::Heap* heap, int num, const sead::SafeString& name, + int a, int b, int c); + + LayerContactPointInfo* makeLayerContactPointInfo(sead::Heap* heap, int num, int num2, + const sead::SafeString& name, int a, int b, + int c); + void registerContactPointInfo(ContactPointInfoBase* info); + void unregisterContactPointInfo(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); + bool registerContactPoint(ContactPointInfo* info, const ContactPoint& point, + const RigidBodyCollisionMasks& colliding_body_masks, + bool penetrating); - // 0x0000007100fb3478 - void x_15(LayerContactPointInfo* info, const ContactPoint& point, bool penetrating); + void registerContactPoint(LayerContactPointInfo* info, const ContactPoint& point, + bool penetrating); - // 0x0000007100fb3744 - void x_17(CollisionInfo* info, RigidBody* body_a, RigidBody* body_b); - // 0x0000007100fb37d4 - void x_18(ContactLayerCollisionInfo* info, RigidBody* body_a, RigidBody* body_b); - // 0x0000007100fb3854 - void x_19(CollisionInfo* info, RigidBody* body_a, RigidBody* body_b); - // 0x0000007100fb3938 - void x_20(ContactLayerCollisionInfo* info, RigidBody* body_a, RigidBody* body_b); - // 0x0000007100fb3a2c - void x_21(ContactLayerCollisionInfo* info, RigidBody* body); + void registerCollision(CollisionInfo* info, RigidBody* body_a, RigidBody* body_b); + void registerCollision(ContactLayerCollisionInfo* info, RigidBody* body_a, RigidBody* body_b); + void unregisterCollision(CollisionInfo* info, RigidBody* body_a, RigidBody* body_b); + void unregisterCollision(ContactLayerCollisionInfo* info, RigidBody* body_a, RigidBody* body_b); + /// Unregister all collision pairs involving the specified rigid body. + void unregisterCollisionWithBody(ContactLayerCollisionInfo* info, RigidBody* body); private: void doLoadContactInfoTable(agl::utl::ResParameterArchive archive, ContactLayerType type, bool skip_params); - // Used to optimise ContactPoint allocations. + /// @return an index into mContactPointPool or -1 if the pool is exhausted. + int allocateContactPoint(); + + void freeCollidingBodiesEntry(CollidingBodies* entry) { + auto lock = sead::makeScopedLock(mCollidingBodiesMutex); + mCollidingBodiesFreeList.pushBack(entry); + } + + /// Used to optimise ContactPoint allocations. sead::Buffer mContactPointPool; - sead::OffsetList mList0; + sead::OffsetList mCollidingBodiesFreeList; int mList0Size = 0; - sead::Atomic _34 = 0; - sead::OffsetList mRigidContactPoints; + /// The index of the next free ContactPoint in the pool. + sead::Atomic mContactPointIndex = 0; + sead::OffsetList mContactPointInfoInstances; sead::OffsetList mList2; sead::OffsetList mList3; sead::OffsetList mList4; sead::OffsetList mList5; - sead::Mutex mMutex1; + // TODO: rename these members + sead::Mutex mContactPointInfoMutex; sead::Mutex mMutex2; sead::Mutex mMutex3; - sead::Mutex mMutex4; + sead::Mutex mCollidingBodiesMutex; sead::Mutex mMutex5; sead::SafeArray mContactInfoTables{}; }; diff --git a/src/KingSystem/Physics/System/physContactPointInfo.h b/src/KingSystem/Physics/System/physContactPointInfo.h index 61313ded..30679e2e 100644 --- a/src/KingSystem/Physics/System/physContactPointInfo.h +++ b/src/KingSystem/Physics/System/physContactPointInfo.h @@ -16,8 +16,12 @@ namespace ksys::phys { +struct ContactPoint; + class ContactPointInfoBase : public sead::INamable { public: + using Points = sead::Buffer; + // FIXME: parameter names ContactPointInfoBase(const sead::SafeString& name, int a, int b, int c) : sead::INamable(name), _2c(a), _30(b), _34(c) {} @@ -41,13 +45,19 @@ public: return mLayerMask2[int(type)].isOnBit(int(getContactLayerBaseRelativeValue(layer))); } +public: + // For internal use by the physics system. + bool isLinked() const { return mListNode.isLinked(); } + static constexpr size_t getListNodeOffset() { return offsetof(ContactPointInfoBase, mListNode); } protected: - sead::Atomic _18; + friend class ContactMgr; + + sead::Atomic mContactPointIndex; sead::SafeArray mSubscribedLayers; // TODO: rename sead::SafeArray mLayerMask2; @@ -86,7 +96,9 @@ public: void setContactCallback(ContactCallback* cb) { mContactCallback = cb; } private: - sead::Buffer mPoints{}; + friend class ContactMgr; + + Points mPoints; ContactCallback* mContactCallback{}; }; KSYS_CHECK_SIZE_NX150(ContactPointInfo, 0x60); diff --git a/src/KingSystem/Physics/System/physLayerContactPointInfo.cpp b/src/KingSystem/Physics/System/physLayerContactPointInfo.cpp index 196f3802..a60602f6 100644 --- a/src/KingSystem/Physics/System/physLayerContactPointInfo.cpp +++ b/src/KingSystem/Physics/System/physLayerContactPointInfo.cpp @@ -67,14 +67,14 @@ void LayerContactPointInfo::Iterator::getData(sead::Vector3f* out, switch (mode) { case Mode::_0: { - if (getPoint()->flags.isOn(ContactPoint::Flag::_2)) + if (getPoint()->flags.isOn(ContactPoint::Flag::Penetrating)) return; *out += getPoint()->separating_normal * -separating_distance; break; } case Mode::_1: { - if (!getPoint()->flags.isOn(ContactPoint::Flag::_2)) + if (!getPoint()->flags.isOn(ContactPoint::Flag::Penetrating)) return; *out += getPoint()->separating_normal * separating_distance; break; diff --git a/src/KingSystem/Physics/System/physLayerContactPointInfo.h b/src/KingSystem/Physics/System/physLayerContactPointInfo.h index 08e9e2c2..72e6c309 100644 --- a/src/KingSystem/Physics/System/physLayerContactPointInfo.h +++ b/src/KingSystem/Physics/System/physLayerContactPointInfo.h @@ -16,8 +16,6 @@ class RigidBody; class LayerContactPointInfo : public ContactPointInfoBase { public: - using Points = sead::Buffer; - struct LayerEntry { ContactLayer layer1; ContactLayer layer2; @@ -115,14 +113,16 @@ public: 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); } + auto begin() const { return Iterator(mPoints, mContactPointIndex); } + auto end() const { return IteratorEnd(mPoints, mContactPointIndex); } sead::ObjArray& getLayerEntries() { return mLayerEntries; } const sead::ObjArray& getLayerEntries() const { return mLayerEntries; } private: - Points mPoints{}; + friend class ContactMgr; + + Points mPoints; sead::ObjArray mLayerEntries; ContactLayerType mLayerType = ContactLayerType::Invalid; ContactCallback* mCallback = nullptr; diff --git a/src/KingSystem/Physics/System/physSystem.cpp b/src/KingSystem/Physics/System/physSystem.cpp index bfad9d89..15d13578 100644 --- a/src/KingSystem/Physics/System/physSystem.cpp +++ b/src/KingSystem/Physics/System/physSystem.cpp @@ -50,7 +50,7 @@ void System::initSystemData(sead::Heap* heap) { ContactPointInfo* System::allocContactPointInfo(sead::Heap* heap, int num, const sead::SafeString& name, int a, int b, int c) const { - return mContactMgr->allocContactPoints(heap, num, name, a, b, c); + return mContactMgr->makeContactPointInfo(heap, num, name, a, b, c); } void System::freeContactPointInfo(ContactPointInfo* info) const { @@ -60,7 +60,7 @@ void System::freeContactPointInfo(ContactPointInfo* info) const { LayerContactPointInfo* System::allocLayerContactPointInfo(sead::Heap* heap, int num, int num2, const sead::SafeString& name, int a, int b, int c) const { - return mContactMgr->allocContactPointsEx(heap, num, num2, name, a, b, c); + return mContactMgr->makeLayerContactPointInfo(heap, num, num2, name, a, b, c); } void System::registerContactPointInfo(ContactPointInfo* info) const {