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
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

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 setNormalOnly(const hkVector4& normal);
/// If negative, the two bodies are penetrating.
inline hkReal getDistance() const;
inline hkSimdReal getDistanceSimdReal() const;
inline void setDistance(hkReal d);

View File

@ -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

View File

@ -10,6 +10,7 @@
#include <thread/seadAtomic.h>
#include <thread/seadCriticalSection.h>
#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<int> mCollisionCount;
void* _c8 = nullptr;
RigidBodyContactCallback* mContactCallback = nullptr;
};
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);
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;

View File

@ -1,8 +1,8 @@
#include "KingSystem/Physics/System/physContactListener.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/hkpContactPointEvent.h>
#include <Havok/Physics2012/Dynamics/Collide/hkpSimpleConstraintContactMgr.h>
#include <Havok/Physics2012/Dynamics/Constraint/Contact/hkpContactPointProperties.h>
#include <Havok/Physics2012/Utilities/CharacterControl/CharacterRigidBody/hkpCharacterRigidBody.h>
#include <math/seadMathCalcCommon.h>
@ -23,6 +23,18 @@ static RigidBody* getRigidBody(hkpRigidBody* hk_body) {
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)
: mMgr(mgr), mLayerType(layer_type), mLayerBase(getContactLayerBase(layer_type)),
mLayerCount(layer_count) {}
@ -88,8 +100,8 @@ void ContactListener::contactPointCallback(const hkpContactPointEvent& event) {
static_cast<void>(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<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,
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,
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) {
event.m_contactPointProperties->m_flags |= hkpContactPointProperties::CONTACT_IS_DISABLED;
disableContact(event);
return false;
}

View File

@ -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,
struct TrackedContactPointLayer {
LayerContactPointInfo* info;
ContactLayer layer;
bool do_not_delay_callback;
};
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() {}
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,
virtual bool
regularContactPointCallback(const hkpContactPointEvent& event, RigidBody* body_a,
RigidBody* body_b,
sead::SafeArray<MaterialMask, 2>* out_material_masks);
sead::SafeArray<MaterialMaskData, 2>* 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<int, int> 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

View File

@ -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<Receiver> 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<Flag, u8> 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

View File

@ -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<int> _18;
sead::SafeArray<sead::BitFlag32, 2> mLayerMask;
sead::SafeArray<sead::BitFlag32, 2> mSubscribedLayers;
// TODO: rename
sead::SafeArray<sead::BitFlag32, 2> mLayerMask2;
u32 _2c{};
u32 _30{};

View File

@ -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;
}
}

View File

@ -6,11 +6,13 @@
#include <prim/seadTypedBitFlag.h>
#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<void*>;
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<const ContactEvent&, bool>;
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<LayerEntry> mLayerEntries;
ContactLayerType mLayerType = ContactLayerType::Invalid;
Callback* mCallback = nullptr;
ContactCallback* mCallback = nullptr;
};
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));
}
inline u32 getShapeKeyOrMinus1(const u32* shape_key) {
return shape_key ? *shape_key : u32(-1);
}
} // namespace ksys::phys

View File

@ -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; }