ksys/phys: Finish ContactListener

This commit is contained in:
Léo Lam 2022-03-03 14:51:55 +01:00
parent 1518cc4960
commit d839816081
No known key found for this signature in database
GPG Key ID: 0DF30F9081000741
14 changed files with 358 additions and 60 deletions

View File

@ -84307,18 +84307,18 @@ Address,Quality,Size,Name
0x0000007100fce54c,O,000048,_ZN4ksys4phys15ContactListener28getContactLayerCollisionInfoEjj 0x0000007100fce54c,O,000048,_ZN4ksys4phys15ContactListener28getContactLayerCollisionInfoEjj
0x0000007100fce57c,O,000308,_ZN4ksys4phys15ContactListener20contactPointCallbackERK20hkpContactPointEvent 0x0000007100fce57c,O,000308,_ZN4ksys4phys15ContactListener20contactPointCallbackERK20hkpContactPointEvent
0x0000007100fce6b0,O,000580,_ZN4ksys4phys15ContactListener28manifoldContactPointCallbackERK20hkpContactPointEventPNS0_9RigidBodyES6_ 0x0000007100fce6b0,O,000580,_ZN4ksys4phys15ContactListener28manifoldContactPointCallbackERK20hkpContactPointEventPNS0_9RigidBodyES6_
0x0000007100fce8f4,U,000764,ksys::phys::ContactListener::m14 0x0000007100fce8f4,O,000764,_ZN4ksys4phys15ContactListener27regularContactPointCallbackERK20hkpContactPointEventPNS0_9RigidBodyES6_PN4sead9SafeArrayINS0_16MaterialMaskDataELi2EEE
0x0000007100fcebf0,U,001052,ksys::phys::ContactListener::x_2 0x0000007100fcebf0,O,001052,_ZN4ksys4phys15ContactListener22notifyContactPointInfoEPNS0_9RigidBodyES3_NS0_12ContactLayerES4_RKNS0_23RigidBodyCollisionMasksES7_RK20hkpContactPointEventb
0x0000007100fcf00c,U,000660,ksys::phys::ContactListener::x_3 0x0000007100fcf00c,M,000660,_ZN4ksys4phys15ContactListener27notifyLayerContactPointInfoERKNS1_24TrackedContactPointLayerEiPNS0_9RigidBodyES6_NS0_12ContactLayerES7_jjRK20hkpContactPointEvent
0x0000007100fcf2a0,O,000356,_ZN4ksys4phys15ContactListener31addLayerPairForContactPointInfoEPNS0_21LayerContactPointInfoENS0_12ContactLayerES4_b 0x0000007100fcf2a0,O,000356,_ZN4ksys4phys15ContactListener31addLayerPairForContactPointInfoEPNS0_21LayerContactPointInfoENS0_12ContactLayerES4_b
0x0000007100fcf404,O,000112,_ZN4ksys4phys15ContactListener35removeLayerPairsForContactPointInfoEPNS0_21LayerContactPointInfoE 0x0000007100fcf404,O,000112,_ZN4ksys4phys15ContactListener35removeLayerPairsForContactPointInfoEPNS0_21LayerContactPointInfoE
0x0000007100fcf474,m,000576,_ZN4ksys4phys15ContactListener34removeLayerPairForContactPointInfoEPNS0_21LayerContactPointInfoENS0_12ContactLayerES4_ 0x0000007100fcf474,m,000576,_ZN4ksys4phys15ContactListener34removeLayerPairForContactPointInfoEPNS0_21LayerContactPointInfoENS0_12ContactLayerES4_
0x0000007100fcf6b4,O,000124,_ZN4ksys4phys15ContactListener14trackLayerPairENS0_12ContactLayerES2_ 0x0000007100fcf6b4,O,000124,_ZN4ksys4phys15ContactListener14trackLayerPairENS0_12ContactLayerES2_
0x0000007100fcf730,O,000156,_ZN4ksys4phys15ContactListener17registerRigidBodyEPNS0_9RigidBodyE 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 0x0000007100fcf7e4,O,000112,_ZNK4ksys4phys15ContactListener27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE
0x0000007100fcf854,O,000092,_ZNK4ksys4phys15ContactListener18getRuntimeTypeInfoEv 0x0000007100fcf854,O,000092,_ZNK4ksys4phys15ContactListener18getRuntimeTypeInfoEv
0x0000007100fcf8b0,O,000004,_ZN4ksys4phys15ContactListener3m11Ev 0x0000007100fcf8b0,O,000004,_ZN4ksys4phys15ContactListener3m11ERK20hkpContactPointEventRKNS0_23RigidBodyCollisionMasksES7_PNS0_9RigidBodyES9_
0x0000007100fcf8b4,O,000008,_ZN4ksys4phys15ContactListener3m15Ev 0x0000007100fcf8b4,O,000008,_ZN4ksys4phys15ContactListener3m15Ev
0x0000007100fcf8bc,O,000072,_ZN4ksys4phys21LayerContactPointInfo4makeEPN4sead4HeapEiiRKNS2_14SafeStringBaseIcEEiii 0x0000007100fcf8bc,O,000072,_ZN4ksys4phys21LayerContactPointInfo4makeEPN4sead4HeapEiiRKNS2_14SafeStringBaseIcEEiii
0x0000007100fcf904,O,000348,_ZN4ksys4phys21LayerContactPointInfo17registerLayerPairENS0_12ContactLayerES2_b 0x0000007100fcf904,O,000348,_ZN4ksys4phys21LayerContactPointInfo17registerLayerPairENS0_12ContactLayerES2_b

Can't render this file because it is too large.

View File

@ -21,6 +21,7 @@ public:
inline void setSeparatingNormal(const hkVector4& separatingNormal); inline void setSeparatingNormal(const hkVector4& separatingNormal);
inline void setNormalOnly(const hkVector4& normal); inline void setNormalOnly(const hkVector4& normal);
/// If negative, the two bodies are penetrating.
inline hkReal getDistance() const; inline hkReal getDistance() const;
inline hkSimdReal getDistanceSimdReal() const; inline hkSimdReal getDistanceSimdReal() const;
inline void setDistance(hkReal d); inline void setDistance(hkReal d);

View File

@ -21,6 +21,7 @@ target_sources(uking PRIVATE
RigidBody/physRigidBody.h RigidBody/physRigidBody.h
RigidBody/physRigidBodyAccessor.cpp RigidBody/physRigidBodyAccessor.cpp
RigidBody/physRigidBodyAccessor.h RigidBody/physRigidBodyAccessor.h
RigidBody/physRigidBodyContactEvent.h
RigidBody/physRigidBodyFromResource.cpp RigidBody/physRigidBodyFromResource.cpp
RigidBody/physRigidBodyFromResource.h RigidBody/physRigidBodyFromResource.h
RigidBody/physRigidBodyFromShape.cpp RigidBody/physRigidBodyFromShape.cpp

View File

@ -10,6 +10,7 @@
#include <thread/seadAtomic.h> #include <thread/seadAtomic.h>
#include <thread/seadCriticalSection.h> #include <thread/seadCriticalSection.h>
#include "KingSystem/Physics/RigidBody/physRigidBodyAccessor.h" #include "KingSystem/Physics/RigidBody/physRigidBodyAccessor.h"
#include "KingSystem/Physics/RigidBody/physRigidBodyContactEvent.h"
#include "KingSystem/Physics/physDefines.h" #include "KingSystem/Physics/physDefines.h"
#include "KingSystem/Utils/Types.h" #include "KingSystem/Utils/Types.h"
@ -551,6 +552,9 @@ public:
/// Get the name of this rigid body or its user. /// Get the name of this rigid body or its user.
virtual const char* getName(); virtual const char* getName();
RigidBodyContactCallback* getContactCallback() const { return mContactCallback; }
void setContactCallback(RigidBodyContactCallback* cb) { mContactCallback = cb; }
// Internal. // Internal.
void setUseSystemTimeFactor(bool use) { mFlags.change(Flag::UseSystemTimeFactor, use); } void setUseSystemTimeFactor(bool use) { mFlags.change(Flag::UseSystemTimeFactor, use); }
// Internal. // Internal.
@ -594,7 +598,7 @@ protected:
Type mType{}; Type mType{};
MotionAccessor* mMotionAccessor = nullptr; MotionAccessor* mMotionAccessor = nullptr;
sead::Atomic<int> mCollisionCount; sead::Atomic<int> mCollisionCount;
void* _c8 = nullptr; RigidBodyContactCallback* mContactCallback = nullptr;
}; };
KSYS_CHECK_SIZE_NX150(RigidBody, 0xD0); KSYS_CHECK_SIZE_NX150(RigidBody, 0xD0);

View File

@ -0,0 +1,21 @@
#pragma once
#include <prim/seadDelegate.h>
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<const RigidBodyContactEvent&, bool>;
} // namespace ksys::phys

View File

@ -84,15 +84,18 @@ private:
}; };
KSYS_CHECK_SIZE_NX150(Unk6, 0x48); KSYS_CHECK_SIZE_NX150(Unk6, 0x48);
struct PointCallback : LayerContactPointInfo::Callback { struct PointCallback : LayerContactPointInfo::ContactCallback {
explicit PointCallback(RigidBodyRequestMgr* mgr_) : mgr(mgr_) {} 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; RigidBodyRequestMgr* mgr;
}; };
// FIXME: rename, implement // FIXME: rename, implement
void someFunction2(void* arg); bool someFunction2(const LayerContactPointInfo::ContactEvent& event);
static void someFunction(void* arg); static void someFunction(void* arg);
static constexpr int NumRigidBodyBuffers = 2; static constexpr int NumRigidBodyBuffers = 2;

View File

@ -1,8 +1,8 @@
#include "KingSystem/Physics/System/physContactListener.h" #include "KingSystem/Physics/System/physContactListener.h"
#include <Havok/Common/Base/Types/Physics/ContactPoint/hkContactPoint.h> #include <Havok/Common/Base/Types/Physics/ContactPoint/hkContactPoint.h>
#include <Havok/Physics2012/Collide/Agent/ContactMgr/hkpContactMgr.h>
#include <Havok/Physics2012/Dynamics/Collide/ContactListener/hkpCollisionEvent.h> #include <Havok/Physics2012/Dynamics/Collide/ContactListener/hkpCollisionEvent.h>
#include <Havok/Physics2012/Dynamics/Collide/ContactListener/hkpContactPointEvent.h> #include <Havok/Physics2012/Dynamics/Collide/ContactListener/hkpContactPointEvent.h>
#include <Havok/Physics2012/Dynamics/Collide/hkpSimpleConstraintContactMgr.h>
#include <Havok/Physics2012/Dynamics/Constraint/Contact/hkpContactPointProperties.h> #include <Havok/Physics2012/Dynamics/Constraint/Contact/hkpContactPointProperties.h>
#include <Havok/Physics2012/Utilities/CharacterControl/CharacterRigidBody/hkpCharacterRigidBody.h> #include <Havok/Physics2012/Utilities/CharacterControl/CharacterRigidBody/hkpCharacterRigidBody.h>
#include <math/seadMathCalcCommon.h> #include <math/seadMathCalcCommon.h>
@ -23,6 +23,18 @@ static RigidBody* getRigidBody(hkpRigidBody* hk_body) {
return reinterpret_cast<RigidBody*>(hk_body->getUserData()); return reinterpret_cast<RigidBody*>(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) ContactListener::ContactListener(ContactMgr* mgr, ContactLayerType layer_type, int layer_count)
: mMgr(mgr), mLayerType(layer_type), mLayerBase(getContactLayerBase(layer_type)), : mMgr(mgr), mLayerType(layer_type), mLayerBase(getContactLayerBase(layer_type)),
mLayerCount(layer_count) {} mLayerCount(layer_count) {}
@ -88,8 +100,8 @@ void ContactListener::contactPointCallback(const hkpContactPointEvent& event) {
static_cast<void>(System::instance()->getGroupFilter(mLayerType)); static_cast<void>(System::instance()->getGroupFilter(mLayerType));
characterControlContactPointCallback(ignored_layers_a, ignored_layers_b, body_a, body_b, contactPointCallbackImpl(ignored_layers_a, ignored_layers_b, body_a, body_b, layer_a,
layer_a, layer_b, event); layer_b, event);
} else if (event.m_type == hkpContactPointEvent::TYPE_MANIFOLD) { } else if (event.m_type == hkpContactPointEvent::TYPE_MANIFOLD) {
manifoldContactPointCallback(event, body_a, body_b); 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_a = filter->getCollisionFilterInfoLayer(masks_a.collision_filter_info);
const auto layer_b = filter->getCollisionFilterInfoLayer(masks_b.collision_filter_info); const auto layer_b = filter->getCollisionFilterInfoLayer(masks_b.collision_filter_info);
if (!characterControlContactPointCallback(masks_a.ignored_layers, masks_b.ignored_layers, if (!contactPointCallbackImpl(masks_a.ignored_layers, masks_b.ignored_layers, body_a, body_b,
body_a, body_b, layer_a, layer_b, event)) { layer_a, layer_b, event)) {
return false; return false;
} }
// Fire ContactPointInfo callbacks.
if (auto* info = body_a->getContactPointInfo(); info && info->getContactCallback()) { if (auto* info = body_a->getContactPointInfo(); info && info->getContactCallback()) {
storeToVec3(&position, event.m_contactPoint->getPosition()); storeToVec3(&position, event.m_contactPoint->getPosition());
storeToVec3(&normal, event.m_contactPoint->getSeparatingNormal()); storeToVec3(&normal, event.m_contactPoint->getSeparatingNormal());
@ -133,8 +147,7 @@ bool ContactListener::manifoldContactPointCallback(const hkpContactPointEvent& e
info->getContactCallback()->invoke(&disable, my_event); info->getContactCallback()->invoke(&disable, my_event);
if (disable == ContactPointInfo::ShouldDisableContact::Yes) { if (disable == ContactPointInfo::ShouldDisableContact::Yes) {
event.m_contactPointProperties->m_flags |= disableContact(event);
hkpContactPointProperties::CONTACT_IS_DISABLED;
return false; return false;
} }
} }
@ -152,8 +165,7 @@ bool ContactListener::manifoldContactPointCallback(const hkpContactPointEvent& e
info->getContactCallback()->invoke(&disable, my_event); info->getContactCallback()->invoke(&disable, my_event);
if (disable == ContactPointInfo::ShouldDisableContact::Yes) { if (disable == ContactPointInfo::ShouldDisableContact::Yes) {
event.m_contactPointProperties->m_flags |= disableContact(event);
hkpContactPointProperties::CONTACT_IS_DISABLED;
return false; return false;
} }
} }
@ -161,6 +173,199 @@ bool ContactListener::manifoldContactPointCallback(const hkpContactPointEvent& e
return true; return true;
} }
bool ContactListener::regularContactPointCallback(
const hkpContactPointEvent& event, RigidBody* body_a, RigidBody* body_b,
sead::SafeArray<MaterialMaskData, 2>* 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, void ContactListener::handleCollisionAdded(const hkpCollisionEvent& event, RigidBody* body_a,
RigidBody* body_b) { RigidBody* body_b) {
registerForEndOfStepContactPointCallbacks(event); registerForEndOfStepContactPointCallbacks(event);
@ -243,7 +448,7 @@ void ContactListener::addLayerPairForContactPointInfo(LayerContactPointInfo* inf
return; return;
entry->info = info; entry->info = info;
entry->layer = layer1; entry->layer = layer1;
entry->enabled = enabled; entry->do_not_delay_callback = enabled;
}; };
auto& row_i = mTrackedContactPointLayers[i]; auto& row_i = mTrackedContactPointLayers[i];
@ -293,12 +498,11 @@ void ContactListener::registerRigidBody(RigidBody* body) {
} }
} }
bool ContactListener::characterControlContactPointCallback(u32 ignored_layers_a, bool ContactListener::contactPointCallbackImpl(u32 ignored_layers_a, u32 ignored_layers_b,
u32 ignored_layers_b, RigidBody* body_a, RigidBody* body_a, RigidBody* body_b,
RigidBody* body_b, ContactLayer layer_a, ContactLayer layer_a, ContactLayer layer_b,
ContactLayer layer_b, const hkpContactPointEvent& event) {
const hkpContactPointEvent& event) { disableContact(event);
event.m_contactPointProperties->m_flags |= hkpContactPointProperties::CONTACT_IS_DISABLED;
return false; return false;
} }

View File

@ -16,6 +16,7 @@ class ContactLayerCollisionInfo;
class ContactMgr; class ContactMgr;
class LayerContactPointInfo; class LayerContactPointInfo;
class RigidBody; class RigidBody;
struct RigidBodyCollisionMasks;
class ContactListener : public hkpContactListener, public sead::hostio::Node { class ContactListener : public hkpContactListener, public sead::hostio::Node {
SEAD_RTTI_BASE(ContactListener) SEAD_RTTI_BASE(ContactListener)
@ -46,12 +47,20 @@ public:
void contactProcessCallback(hkpContactProcessEvent& event) override {} void contactProcessCallback(hkpContactProcessEvent& event) override {}
protected: protected:
virtual bool characterControlContactPointCallback(u32 ignored_layers_a, u32 ignored_layers_b, struct TrackedContactPointLayer {
RigidBody* body_a, RigidBody* body_b, LayerContactPointInfo* info;
ContactLayer layer_a, ContactLayer layer_b, ContactLayer layer;
const hkpContactPointEvent& event); 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, virtual void handleCollisionAdded(const hkpCollisionEvent& event, RigidBody* body_a,
RigidBody* body_b); RigidBody* body_b);
@ -63,23 +72,30 @@ protected:
RigidBody* body_b); RigidBody* body_b);
/// @param out_material_masks [Optional] Pass this to get the materials of the rigid bodies. /// @param out_material_masks [Optional] Pass this to get the materials of the rigid bodies.
virtual bool regularContactPointCallback(const hkpContactPointEvent& event, RigidBody* body_a, virtual bool
RigidBody* body_b, regularContactPointCallback(const hkpContactPointEvent& event, RigidBody* body_a,
sead::SafeArray<MaterialMask, 2>* out_material_masks); RigidBody* body_b,
sead::SafeArray<MaterialMaskData, 2>* out_material_masks);
virtual u32 m15() { return 0; } 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<int, int> convertToRelativeLayer(ContactLayer layer1, ContactLayer layer2) const { std::pair<int, int> convertToRelativeLayer(ContactLayer layer1, ContactLayer layer2) const {
return {layer1 - int(mLayerBase), layer2 - int(mLayerBase)}; return {layer1 - int(mLayerBase), layer2 - int(mLayerBase)};
} }
private: private:
struct TrackedContactPointLayer {
LayerContactPointInfo* info;
ContactLayer layer;
bool enabled;
};
ContactMgr* mMgr{}; ContactMgr* mMgr{};
ContactLayerType mLayerType{}; ContactLayerType mLayerType{};
u32 mLayerBase{}; u32 mLayerBase{};
@ -91,7 +107,7 @@ private:
u32 mLayerCount{}; u32 mLayerCount{};
sead::CriticalSection mCS; sead::CriticalSection mCS;
u16 _90{}; u16 _90{};
bool _92{}; bool mDisableContactPointInfoNotifications = false;
}; };
} // namespace ksys::phys } // namespace ksys::phys

View File

@ -28,6 +28,7 @@ class CollisionInfo;
class ContactLayerCollisionInfo; class ContactLayerCollisionInfo;
class ContactPointInfoBase; class ContactPointInfoBase;
class RigidBody; class RigidBody;
struct RigidBodyCollisionMasks;
class ContactPointInfo; class ContactPointInfo;
class LayerContactPointInfo; class LayerContactPointInfo;
@ -49,21 +50,21 @@ struct ContactInfoTable {
sead::Buffer<Receiver> receivers; sead::Buffer<Receiver> receivers;
}; };
// XXX: what exactly is this? Is this really a contact point?
struct ContactPoint { struct ContactPoint {
enum class Flag { enum class Flag {
_1 = 1 << 0, _1 = 1 << 0,
_2 = 1 << 1, _2 = 1 << 1,
}; };
void* _0; RigidBody* body_a;
void* _8; RigidBody* body_b;
sead::Vector3f _10; sead::Vector3f position;
sead::Vector3f _1c; sead::Vector3f separating_normal;
float scale; float separating_distance;
MaterialMask material_mask1; MaterialMask material_mask_a;
MaterialMask material_mask2; MaterialMask material_mask_b;
void* _60; u32 shape_key_a;
u32 shape_key_b;
sead::TypedBitFlag<Flag, u8> flags; sead::TypedBitFlag<Flag, u8> flags;
}; };
KSYS_CHECK_SIZE_NX150(ContactPoint, 0x70); KSYS_CHECK_SIZE_NX150(ContactPoint, 0x70);
@ -90,6 +91,15 @@ public:
void registerContactPointInfo(ContactPointInfoBase* info); void registerContactPointInfo(ContactPointInfoBase* info);
void freeContactPointInfo(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 // 0x0000007100fb3744
void x_17(CollisionInfo* info, RigidBody* body_a, RigidBody* body_b); void x_17(CollisionInfo* info, RigidBody* body_a, RigidBody* body_b);
// 0x0000007100fb37d4 // 0x0000007100fb37d4

View File

@ -24,8 +24,23 @@ public:
virtual ~ContactPointInfoBase() = default; virtual ~ContactPointInfoBase() = default;
virtual void freePoints() = 0; virtual void freePoints() = 0;
u32 get30() const { return _30; }
void set30(u32 value) { _30 = value; } 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(); } bool isLinked() const { return mListNode.isLinked(); }
static constexpr size_t getListNodeOffset() { static constexpr size_t getListNodeOffset() {
return offsetof(ContactPointInfoBase, mListNode); return offsetof(ContactPointInfoBase, mListNode);
@ -33,7 +48,8 @@ public:
protected: protected:
sead::Atomic<int> _18; sead::Atomic<int> _18;
sead::SafeArray<sead::BitFlag32, 2> mLayerMask; sead::SafeArray<sead::BitFlag32, 2> mSubscribedLayers;
// TODO: rename
sead::SafeArray<sead::BitFlag32, 2> mLayerMask2; sead::SafeArray<sead::BitFlag32, 2> mLayerMask2;
u32 _2c{}; u32 _2c{};
u32 _30{}; u32 _30{};

View File

@ -62,27 +62,27 @@ void LayerContactPointInfo::freePoints() {
void LayerContactPointInfo::Iterator::getData(sead::Vector3f* out, void LayerContactPointInfo::Iterator::getData(sead::Vector3f* out,
LayerContactPointInfo::Iterator::Mode mode) const { LayerContactPointInfo::Iterator::Mode mode) const {
const float scale = getPoint()->scale; const float separating_distance = getPoint()->separating_distance;
out->e = getPoint()->_10.e; out->e = getPoint()->position.e;
switch (mode) { switch (mode) {
case Mode::_0: { case Mode::_0: {
if (getPoint()->flags.isOn(ContactPoint::Flag::_2)) if (getPoint()->flags.isOn(ContactPoint::Flag::_2))
return; return;
*out += getPoint()->_1c * -scale; *out += getPoint()->separating_normal * -separating_distance;
break; break;
} }
case Mode::_1: { case Mode::_1: {
if (!getPoint()->flags.isOn(ContactPoint::Flag::_2)) if (!getPoint()->flags.isOn(ContactPoint::Flag::_2))
return; return;
*out += getPoint()->_1c * scale; *out += getPoint()->separating_normal * separating_distance;
break; break;
} }
case Mode::_2: case Mode::_2:
default: { default: {
*out += getPoint()->_1c * scale * 0.5f; *out += getPoint()->separating_normal * separating_distance * 0.5f;
break; break;
} }
} }

View File

@ -6,11 +6,13 @@
#include <prim/seadTypedBitFlag.h> #include <prim/seadTypedBitFlag.h>
#include "KingSystem/Physics/System/physContactPointInfo.h" #include "KingSystem/Physics/System/physContactPointInfo.h"
#include "KingSystem/Physics/physDefines.h" #include "KingSystem/Physics/physDefines.h"
#include "KingSystem/Physics/physMaterialMask.h"
#include "KingSystem/Utils/Types.h" #include "KingSystem/Utils/Types.h"
namespace ksys::phys { namespace ksys::phys {
struct ContactPoint; struct ContactPoint;
class RigidBody;
class LayerContactPointInfo : public ContactPointInfoBase { class LayerContactPointInfo : public ContactPointInfoBase {
public: public:
@ -86,8 +88,17 @@ public:
const ContactPoint* const* mPointsStart = nullptr; const ContactPoint* const* mPointsStart = nullptr;
}; };
// FIXME: figure out the types struct ContactEvent {
using Callback = sead::IDelegate1<void*>; 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<const ContactEvent&, bool>;
static LayerContactPointInfo* make(sead::Heap* heap, int num, int num2, static LayerContactPointInfo* make(sead::Heap* heap, int num, int num2,
const sead::SafeString& name, int a, int b, int c); 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 registerLayerPair(ContactLayer layer1, ContactLayer layer2, bool enabled = true);
bool isPairUnknown(ContactLayer layer1, ContactLayer layer2) const; 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 begin() const { return Iterator(mPoints, _18); }
auto end() const { return IteratorEnd(mPoints, _18); } auto end() const { return IteratorEnd(mPoints, _18); }
@ -113,7 +125,7 @@ private:
Points mPoints{}; Points mPoints{};
sead::ObjArray<LayerEntry> mLayerEntries; sead::ObjArray<LayerEntry> mLayerEntries;
ContactLayerType mLayerType = ContactLayerType::Invalid; ContactLayerType mLayerType = ContactLayerType::Invalid;
Callback* mCallback = nullptr; ContactCallback* mCallback = nullptr;
}; };
KSYS_CHECK_SIZE_NX150(LayerContactPointInfo, 0x88); KSYS_CHECK_SIZE_NX150(LayerContactPointInfo, 0x88);

View File

@ -92,4 +92,8 @@ inline void setMtxTranslation(sead::Matrix34f* mtx, const hkVector4f& translatio
mtx->setTranslation(toVec3(translation)); mtx->setTranslation(toVec3(translation));
} }
inline u32 getShapeKeyOrMinus1(const u32* shape_key) {
return shape_key ? *shape_key : u32(-1);
}
} // namespace ksys::phys } // namespace ksys::phys

View File

@ -50,7 +50,7 @@ static_assert(sizeof(MaterialMaskData) == sizeof(u32));
class MaterialMask { class MaterialMask {
public: public:
MaterialMask(); 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, FloorCode floor, WallCode wall, bool flag = false);
MaterialMask(Material mat, const char* submat_name, FloorCode floor, WallCode wall, MaterialMask(Material mat, const char* submat_name, FloorCode floor, WallCode wall,
bool flag = false); bool flag = false);
@ -66,6 +66,12 @@ public:
return *this; return *this;
} }
MaterialMask& operator=(MaterialMaskData data) {
mData = data;
mSubMaterialNameCache = nullptr;
return *this;
}
MaterialMaskData& getData() { return mData; } MaterialMaskData& getData() { return mData; }
const MaterialMaskData& getData() const { return mData; } const MaterialMaskData& getData() const { return mData; }
u32 getRawData() const { return mData.raw; } u32 getRawData() const { return mData.raw; }