ksys/phys: Finish EntityContactListener

This commit is contained in:
Léo Lam 2022-03-09 00:03:15 +01:00
parent 8cbdcbf6ea
commit 0e717ed15d
No known key found for this signature in database
GPG Key ID: 0DF30F9081000741
18 changed files with 629 additions and 60 deletions

View File

@ -83827,7 +83827,7 @@ Address,Quality,Size,Name
0x0000007100fb6134,O,000008,_ZN14hkpGroupFilter11dummyUnusedEv
0x0000007100fb613c,O,000204,_ZNK4ksys4phys17EntityGroupFilter27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE
0x0000007100fb6208,O,000092,_ZNK4ksys4phys17EntityGroupFilter18getRuntimeTypeInfoEv
0x0000007100fb6264,O,000044,_ZN4ksys4phys17EntityGroupFilter2m2ENS0_12ContactLayerES2_
0x0000007100fb6264,O,000044,_ZN4ksys4phys17EntityGroupFilter27shouldContactNeverBeIgnoredENS0_12ContactLayerES2_
0x0000007100fb6290,O,000028,_ZN4ksys4phys17EntityGroupFilter23makeCollisionFilterInfoENS0_12ContactLayerENS0_9GroundHitE
0x0000007100fb62ac,O,000020,_ZN4ksys4phys17EntityGroupFilter27getCollisionFilterInfoLayerEj
0x0000007100fb62c0,O,000028,_ZN4ksys4phys17EntityGroupFilter22makeQueryCollisionMaskEjNS0_9GroundHitEb
@ -83842,18 +83842,18 @@ Address,Quality,Size,Name
0x0000007100fb643c,O,000108,_ZN4ksys4phys21EntityContactListener4makeEPNS0_10ContactMgrEPN4sead4HeapE
0x0000007100fb64a8,O,000004,_ZN4ksys4phys21EntityContactListenerD1Ev
0x0000007100fb64ac,O,000036,_ZN4ksys4phys21EntityContactListenerD0Ev
0x0000007100fb64d0,U,000456,
0x0000007100fb6698,U,000472,
0x0000007100fb6870,U,000320,
0x0000007100fb69b0,U,000304,
0x0000007100fb6ae0,U,000492,
0x0000007100fb6ccc,U,000120,
0x0000007100fb64d0,O,000456,_ZN4ksys4phys21EntityContactListener22collisionAddedCallbackERK17hkpCollisionEvent
0x0000007100fb6698,O,000472,_ZN4ksys4phys21EntityContactListener37setMagneMassScalingForContactIfNeededERK17hkpCollisionEventPNS0_9RigidBodyES6_
0x0000007100fb6870,O,000320,_ZN4ksys4phys21EntityContactListener34setImpulseScalingForTerrainContactERK17hkpCollisionEventPNS0_9RigidBodyES6_
0x0000007100fb69b0,O,000304,_ZN4ksys4phys21EntityContactListener24collisionRemovedCallbackERK17hkpCollisionEvent
0x0000007100fb6ae0,O,000492,_ZN4ksys4phys21EntityContactListener40removeViscousSurfaceModifierAndCollisionERK17hkpCollisionEventPNS0_9RigidBodyES6_
0x0000007100fb6ccc,O,000120,_ZN4ksys4phys21EntityContactListener3m15EPNS0_9RigidBodyES3_
0x0000007100fb6d44,O,000084,_ZN4ksys4phys21EntityContactListener27isObjectOrGroundOrNPCOrTreeERKNS0_9RigidBodyE
0x0000007100fb6d98,O,000128,_ZN4ksys4phys21EntityContactListener27isObjectOrGroundOrNPCOrTreeERK9hkpCdBody
0x0000007100fb6e18,U,000460,
0x0000007100fb6e18,O,000460,_ZN4ksys4phys21EntityContactListener24contactPointCallbackImplEjjPNS0_9RigidBodyES3_NS0_12ContactLayerES4_RK20hkpContactPointEvent
0x0000007100fb6fe4,O,000284,_ZN4ksys4phys21EntityContactListener3m11ERK20hkpContactPointEventRKNS0_23RigidBodyCollisionMasksES7_PNS0_9RigidBodyES9_
0x0000007100fb7100,U,000344,
0x0000007100fb7258,U,002036,
0x0000007100fb7100,O,000344,_ZN4ksys4phys21EntityContactListener29setMagneMassScalingForContactERK17hkpCollisionEventPNS0_9RigidBodyES6_
0x0000007100fb7258,m,002036,_ZN4ksys4phys21EntityContactListener27regularContactPointCallbackERK20hkpContactPointEventPNS0_9RigidBodyES6_PN4sead9SafeArrayIjLi2EEE
0x0000007100fb7a4c,O,000204,_ZNK4ksys4phys21EntityContactListener27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE
0x0000007100fb7b18,O,000092,_ZNK4ksys4phys21EntityContactListener18getRuntimeTypeInfoEv
0x0000007100fb7b74,O,000140,_ZNK4sead15RuntimeTypeInfo6DeriveIN4ksys4phys15ContactListenerEE9isDerivedEPKNS0_9InterfaceE
@ -84150,7 +84150,7 @@ Address,Quality,Size,Name
0x0000007100fc8528,O,000004,_ZN4ksys4phys24SensorSystemGroupHandlerD0Ev
0x0000007100fc852c,O,000204,_ZNK4ksys4phys17SensorGroupFilter27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE
0x0000007100fc85f8,O,000092,_ZNK4ksys4phys17SensorGroupFilter18getRuntimeTypeInfoEv
0x0000007100fc8654,O,000008,_ZN4ksys4phys11GroupFilter2m2ENS0_12ContactLayerES2_
0x0000007100fc8654,O,000008,_ZN4ksys4phys11GroupFilter27shouldContactNeverBeIgnoredENS0_12ContactLayerES2_
0x0000007100fc865c,O,000048,_ZN4ksys4phys17SensorGroupFilter23makeCollisionFilterInfoENS0_12ContactLayerENS0_9GroundHitE
0x0000007100fc868c,O,000024,_ZN4ksys4phys17SensorGroupFilter27getCollisionFilterInfoLayerEj
0x0000007100fc86a4,O,000008,_ZN4ksys4phys17SensorGroupFilter22makeQueryCollisionMaskEjNS0_9GroundHitEb
@ -84307,7 +84307,7 @@ Address,Quality,Size,Name
0x0000007100fce54c,O,000048,_ZN4ksys4phys15ContactListener28getContactLayerCollisionInfoEjj
0x0000007100fce57c,O,000308,_ZN4ksys4phys15ContactListener20contactPointCallbackERK20hkpContactPointEvent
0x0000007100fce6b0,O,000580,_ZN4ksys4phys15ContactListener28manifoldContactPointCallbackERK20hkpContactPointEventPNS0_9RigidBodyES6_
0x0000007100fce8f4,O,000764,_ZN4ksys4phys15ContactListener27regularContactPointCallbackERK20hkpContactPointEventPNS0_9RigidBodyES6_PN4sead9SafeArrayINS0_16MaterialMaskDataELi2EEE
0x0000007100fce8f4,O,000764,_ZN4ksys4phys15ContactListener27regularContactPointCallbackERK20hkpContactPointEventPNS0_9RigidBodyES6_PN4sead9SafeArrayIjLi2EEE
0x0000007100fcebf0,O,001052,_ZN4ksys4phys15ContactListener22notifyContactPointInfoEPNS0_9RigidBodyES3_NS0_12ContactLayerES4_RKNS0_23RigidBodyCollisionMasksES7_RK20hkpContactPointEventb
0x0000007100fcf00c,M,000660,_ZN4ksys4phys15ContactListener27notifyLayerContactPointInfoERKNS1_24TrackedContactPointLayerEiPNS0_9RigidBodyES6_NS0_12ContactLayerES7_jjRK20hkpContactPointEvent
0x0000007100fcf2a0,O,000356,_ZN4ksys4phys15ContactListener31addLayerPairForContactPointInfoEPNS0_21LayerContactPointInfoENS0_12ContactLayerES4_b
@ -84319,7 +84319,7 @@ Address,Quality,Size,Name
0x0000007100fcf7e4,O,000112,_ZNK4ksys4phys15ContactListener27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE
0x0000007100fcf854,O,000092,_ZNK4ksys4phys15ContactListener18getRuntimeTypeInfoEv
0x0000007100fcf8b0,O,000004,_ZN4ksys4phys15ContactListener3m11ERK20hkpContactPointEventRKNS0_23RigidBodyCollisionMasksES7_PNS0_9RigidBodyES9_
0x0000007100fcf8b4,O,000008,_ZN4ksys4phys15ContactListener3m15Ev
0x0000007100fcf8b4,O,000008,_ZN4ksys4phys15ContactListener3m15EPNS0_9RigidBodyES3_
0x0000007100fcf8bc,O,000072,_ZN4ksys4phys21LayerContactPointInfo4makeEPN4sead4HeapEiiRKNS2_14SafeStringBaseIcEEiii
0x0000007100fcf904,O,000348,_ZN4ksys4phys21LayerContactPointInfo17registerLayerPairENS0_12ContactLayerES2_b
0x0000007100fcfa60,O,000024,_ZN4ksys4phys21LayerContactPointInfo4freeEPS1_

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

View File

@ -179,6 +179,7 @@ add_library(hkStubs OBJECT
Havok/Physics2012/Dynamics/World/Memory/hkpWorldMemoryAvailableWatchDog.h
Havok/Physics2012/Dynamics/World/Memory/Default/hkpDefaultWorldMemoryWatchDog.h
Havok/Physics2012/Dynamics/World/Simulation/hkpSimulation.h
Havok/Physics2012/Dynamics/World/Util/hkpWorldConstraintUtil.h
Havok/Physics2012/Internal/Collide/Mopp/Code/hkpMoppCode.h
Havok/Physics2012/Internal/Solver/Contact/hkpSimpleContactConstraintDataInfo.h

View File

@ -14,7 +14,7 @@ public:
HK_DECLARE_CLASS_ALLOCATOR(hkpConstraintData)
HK_DECLARE_REFLECTION()
enum ConstraintType {
enum ConstraintType : int {
CONSTRAINT_TYPE_BALLANDSOCKET = 0,
CONSTRAINT_TYPE_HINGE = 1,
CONSTRAINT_TYPE_LIMITEDHINGE = 2,
@ -65,7 +65,7 @@ public:
explicit hkpConstraintData(hkFinishLoadedObjectFlag f);
HK_FORCE_INLINE ~hkpConstraintData() override;
virtual int getType() const = 0;
virtual ConstraintType getType() const = 0;
virtual void getConstraintInfo(ConstraintInfo& infoOut) const = 0;
virtual hkBool isValid() const = 0;

View File

@ -35,7 +35,7 @@ public:
void getConstraintInfo(hkpConstraintData::ConstraintInfo& infoOut) const override;
void getRuntimeInfo(hkBool wantRuntime, hkpConstraintData::RuntimeInfo& infoOut) const override;
hkpSolverResults* getSolverResults(hkpConstraintRuntime* runtime) const override;
int getType() const override;
ConstraintType getType() const override;
virtual void collisionResponseBeginCallback(const hkContactPoint& cp,
struct hkpSimpleConstraintInfoInitInput& inA,

View File

@ -0,0 +1,41 @@
#pragma once
#include <Havok/Common/Base/hkBase.h>
#include <Havok/Physics/Constraint/Atom/hkpConstraintAtom.h>
struct hkConstraintInternal;
class hkpConstraintInstance;
class hkpConstraintOwner;
class hkpEntity;
struct hkpModifierConstraintAtom;
class hkpWorld;
class hkpWorldConstraintUtil {
public:
static void addConstraint(hkpWorld* world, hkpConstraintInstance* constraint);
static void removeConstraint(hkpConstraintInstance* constraint);
static hkpConstraintInstance* getConstraint(const hkpEntity* entityA, const hkpEntity* entityB);
static void addModifier(hkpConstraintInstance* instance, hkpConstraintOwner& constraintOwner,
hkpModifierConstraintAtom* s);
static void removeAndDeleteModifier(hkpConstraintInstance* instance,
hkpConstraintOwner& constraintOwner,
hkpConstraintAtom::AtomType type);
static hkpModifierConstraintAtom* findModifier(hkpConstraintInstance* instance,
hkpConstraintAtom::AtomType type);
static hkpModifierConstraintAtom* findLastModifier(hkpConstraintInstance* instance);
static void updateFatherOfMovedAtom(hkpConstraintInstance* instance,
const hkpConstraintAtom* oldAtom,
const hkpConstraintAtom* updatedAtom,
int updatedSizeOfAtom);
HK_FORCE_INLINE static hkpConstraintAtom*
getTerminalAtom(const hkConstraintInternal* cInternal);
};

View File

@ -87,6 +87,8 @@ target_sources(uking PRIVATE
RigidBody/TeraMesh/physTeraMeshRigidBodyResource.cpp
RigidBody/TeraMesh/physTeraMeshRigidBodyResource.h
RigidBody/TerrainHeightField/physTerrainHeightFieldRigidBody.h
StaticCompound/physStaticCompound.cpp
StaticCompound/physStaticCompound.h
StaticCompound/physStaticCompoundAutogen.cpp

View File

@ -0,0 +1,17 @@
#pragma once
#include "KingSystem/Physics/RigidBody/physRigidBody.h"
namespace ksys::phys {
class TerrainHeightFieldRigidBody : public RigidBody {
SEAD_RTTI_OVERRIDE(TerrainHeightFieldRigidBody, RigidBody)
public:
bool getD8() const { return _d8; }
private:
void* _d0{};
bool _d8 = false;
};
} // namespace ksys::phys

View File

@ -30,6 +30,12 @@ public:
_200 = 1 << 9,
};
enum class ContactFlag {
_1 = 1 << 0,
_2 = 1 << 1,
_4 = 1 << 2,
};
explicit RigidBodyMotionEntity(RigidBody* body);
void setTransform(const sead::Matrix34f& mtx, bool propagate_to_linked_motions) override;
@ -122,6 +128,9 @@ public:
void resetFlag(Flag flag) { mFlags.reset(flag); }
void changeFlag(Flag flag, bool on) { mFlags.change(flag, on); }
auto& getContactFlags() { return mContactFlags; }
auto& getContactFlags() const { return mContactFlags; }
static void setImpulseEpsilon(float epsilon);
static void setDefaultMaxImpulse(float max_impulse);
@ -152,7 +161,7 @@ private:
float mRestitutionScale = 1.0f;
float mMaxImpulse = -1.0f;
float mColImpulseScale = 1.0f;
sead::Atomic<u32> _c4;
sead::TypedBitFlag<ContactFlag, sead::Atomic<u32>> mContactFlags;
sead::TypedBitFlag<Flag, sead::Atomic<u32>> mFlags;
u32 _cc{};
sead::CriticalSection mCS;

View File

@ -18,18 +18,6 @@
namespace ksys::phys {
static void clearCallbackDelay(const hkpContactPointEvent& event) {
event.m_contactMgr->m_contactPointCallbackDelay = 0;
}
static void disableContact(const hkpContactPointEvent& event) {
event.m_contactPointProperties->m_flags |= hkpContactPointProperties::CONTACT_IS_DISABLED;
}
static bool isContactDisabled(const hkpContactPointEvent& event) {
return event.m_contactPointProperties->m_flags & hkpContactPointProperties::CONTACT_IS_DISABLED;
}
ContactListener::ContactListener(ContactMgr* mgr, ContactLayerType layer_type, int layer_count)
: mMgr(mgr), mLayerType(layer_type), mLayerBase(getContactLayerBase(layer_type)),
mLayerCount(layer_count) {}
@ -168,9 +156,9 @@ bool ContactListener::manifoldContactPointCallback(const hkpContactPointEvent& e
return true;
}
bool ContactListener::regularContactPointCallback(
const hkpContactPointEvent& event, RigidBody* body_a, RigidBody* body_b,
sead::SafeArray<MaterialMaskData, 2>* out_material_masks) {
bool ContactListener::regularContactPointCallback(const hkpContactPointEvent& event,
RigidBody* body_a, RigidBody* body_b,
sead::SafeArray<u32, 2>* out_material_masks) {
auto* filter = System::instance()->getGroupFilter(mLayerType);
RigidBody::CollisionMasks masks_a, masks_b;
@ -181,8 +169,8 @@ bool ContactListener::regularContactPointCallback(
body_b->getCollisionMasks(&masks_b, event.getShapeKeys(1), contact_point_pos);
if (out_material_masks) {
(*out_material_masks)[0] = MaterialMaskData(masks_a.material_mask);
(*out_material_masks)[1] = MaterialMaskData(masks_b.material_mask);
(*out_material_masks)[0] = masks_a.material_mask;
(*out_material_masks)[1] = masks_b.material_mask;
}
const auto layer_a = filter->getCollisionFilterInfoLayer(masks_a.collision_filter_info);

View File

@ -1,6 +1,9 @@
#pragma once
#include <Havok/Physics2012/Dynamics/Collide/ContactListener/hkpContactListener.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 <container/seadBuffer.h>
#include <container/seadObjArray.h>
#include <hostio/seadHostIONode.h>
@ -46,6 +49,23 @@ public:
void contactPointRemovedCallback(hkpContactPointRemovedEvent& event) override {}
void contactProcessCallback(hkpContactProcessEvent& event) override {}
static void clearCallbackDelay(const hkpContactPointEvent& event) {
event.m_contactMgr->m_contactPointCallbackDelay = 0;
}
static void enableContact(const hkpContactPointEvent& event) {
event.m_contactPointProperties->m_flags &= ~hkpContactPointProperties::CONTACT_IS_DISABLED;
}
static void disableContact(const hkpContactPointEvent& event) {
event.m_contactPointProperties->m_flags |= hkpContactPointProperties::CONTACT_IS_DISABLED;
}
static bool isContactDisabled(const hkpContactPointEvent& event) {
return event.m_contactPointProperties->m_flags &
hkpContactPointProperties::CONTACT_IS_DISABLED;
}
protected:
struct TrackedContactPointLayer {
LayerContactPointInfo* info;
@ -72,12 +92,11 @@ protected:
RigidBody* body_b);
/// @param out_material_masks [Optional] Pass this to get the materials of the rigid bodies.
virtual bool
regularContactPointCallback(const hkpContactPointEvent& event, RigidBody* body_a,
RigidBody* body_b,
sead::SafeArray<MaterialMaskData, 2>* out_material_masks);
virtual bool regularContactPointCallback(const hkpContactPointEvent& event, RigidBody* body_a,
RigidBody* body_b,
sead::SafeArray<u32, 2>* out_material_masks);
virtual u32 m15() { return 0; }
virtual bool m15(RigidBody* body_a, RigidBody* body_b) { return false; }
/// Record a contact point in the ContactPointInfo instances of the bodies (if applicable).
int notifyContactPointInfo(RigidBody* body_a, RigidBody* body_b, ContactLayer layer_a,
@ -95,7 +114,7 @@ protected:
return {layer1 - int(mLayerBase), layer2 - int(mLayerBase)};
}
private:
protected:
ContactMgr* mMgr{};
ContactLayerType mLayerType{};
u32 mLayerBase{};
@ -106,7 +125,8 @@ private:
u32 mTrackedLayersBufferSize{};
u32 mLayerCount{};
sead::CriticalSection mCS;
u16 _90{};
bool _90 = false;
bool _91 = false;
bool mDisableContactPointInfoNotifications = false;
};

View File

@ -146,8 +146,8 @@ public:
// 0x0000007100fb4228
void x_26(RigidBody* body_a, RigidBody* body_b);
// 0x0000007100fb42f4
void x_27(RigidBody* body_a, RigidBody* body_b, const sead::Vector3f&, const sead::Vector3f&,
u32 material_a, u32 material_b);
void x_27(RigidBody* body_a, RigidBody* body_b, const sead::Vector3f& point_position,
const sead::Vector3f& point_separating_normal, u32 material_a, u32 material_b);
// 0x0000007100fb4738
void x_28(void* unk);
// 0x0000007100fb49d4

View File

@ -1,9 +1,17 @@
#include "KingSystem/Physics/System/physEntityContactListener.h"
#include <Havok/Physics2012/Collide/Agent/Collidable/hkpCdBody.h>
#include <Havok/Physics2012/Dynamics/Collide/ContactListener/hkpContactPointEvent.h>
#include <Havok/Physics2012/Dynamics/Collide/hkpResponseModifier.h>
#include <Havok/Physics2012/Dynamics/Collide/hkpSimpleConstraintContactMgr.h>
#include <Havok/Physics2012/Dynamics/Constraint/Contact/hkpContactPointProperties.h>
#include <Havok/Physics2012/Dynamics/World/Util/hkpWorldConstraintUtil.h>
#include <Havok/Physics2012/Dynamics/World/hkpSimulationIsland.h>
#include <math/seadMathCalcCommon.h>
#include "KingSystem/Physics/RigidBody/TerrainHeightField/physTerrainHeightFieldRigidBody.h"
#include "KingSystem/Physics/RigidBody/physRigidBody.h"
#include "KingSystem/Physics/RigidBody/physRigidBodyMotionEntity.h"
#include "KingSystem/Physics/System/physContactMgr.h"
#include "KingSystem/Physics/System/physGroupFilter.h"
#include "KingSystem/Physics/System/physMaterialTable.h"
#include "KingSystem/Physics/System/physSystem.h"
#include "KingSystem/Physics/physConversions.h"
@ -11,6 +19,49 @@
namespace ksys::phys {
using ContactFlag = RigidBodyMotionEntity::ContactFlag;
static bool shouldProcessEntityContact(sead::BitFlag32 ignored_layers_a,
sead::BitFlag32 ignored_layers_b, ContactLayer layer_a,
ContactLayer layer_b) {
auto* filter = System::instance()->getGroupFilter(ContactLayerType::Entity);
return filter->shouldContactNeverBeIgnored(layer_a, layer_b) ||
ignored_layers_a.isOffBit(layer_b) || ignored_layers_b.isOffBit(layer_a);
}
static bool shouldProcessEntityContact(u32 ignored_layers_a, u32 ignored_layers_b,
ContactLayer layer_a, ContactLayer layer_b) {
return shouldProcessEntityContact(sead::BitFlag32(ignored_layers_a),
sead::BitFlag32(ignored_layers_b), layer_a, layer_b);
}
static bool shouldProcessEntityContact(const RigidBody* body_a, const RigidBody* body_b) {
const auto ignored_layers_a = body_a->getIgnoredLayers();
const auto ignored_layers_b = body_b->getIgnoredLayers();
const auto layer_a = body_a->getContactLayer();
const auto layer_b = body_b->getContactLayer();
return shouldProcessEntityContact(ignored_layers_a, ignored_layers_b, layer_a, layer_b);
}
// TODO: rename
static bool hasEntityWithMotionFlag80(const hkpCollisionEvent& event) {
bool has_flag_80 = false;
auto* island = event.getSimulationIsland();
for (int i = 0; i < island->getEntities().getSize(); ++i) {
auto* entity = getHkpEntity(*island->getEntities()[i]->getCollidable());
if (!entity)
continue;
bool on = getRigidBody(entity)->isEntityMotionFlag80On();
has_flag_80 |= on;
if (on)
break;
}
return has_flag_80;
}
EntityContactListener* EntityContactListener::make(ContactMgr* mgr, sead::Heap* heap) {
auto* listener = new (heap) EntityContactListener(mgr, heap);
listener->init(heap);
@ -22,6 +73,60 @@ EntityContactListener::EntityContactListener(ContactMgr* mgr, sead::Heap* heap)
EntityContactListener::~EntityContactListener() = default;
void EntityContactListener::collisionAddedCallback(const hkpCollisionEvent& event) {
auto* body_a = getRigidBody(event.getBody(0));
auto* body_b = getRigidBody(event.getBody(1));
handleCollisionAdded(event, body_a, body_b);
const auto ignored_layers_a = body_a->getIgnoredLayers();
const auto ignored_layers_b = body_b->getIgnoredLayers();
const auto layer_a = body_a->getContactLayer();
const auto layer_b = body_b->getContactLayer();
bool should_process =
shouldProcessEntityContact(ignored_layers_a, ignored_layers_b, layer_a, layer_b);
if (!should_process) {
setMagneMassScalingForContactIfNeeded(event, body_a, body_b);
setImpulseScalingForTerrainContact(event, body_a, body_b);
}
if ((layer_a == ContactLayer::EntityWater &&
body_b->getType() != RigidBody::Type::CharacterController) ||
(layer_b == ContactLayer::EntityWater &&
body_a->getType() != RigidBody::Type::CharacterController)) {
body_a->onCollisionAdded();
body_b->onCollisionAdded();
}
if (!should_process && m15(body_a, body_b)) {
mMgr->x_26(body_a, body_b);
}
}
void EntityContactListener::collisionRemovedCallback(const hkpCollisionEvent& event) {
auto* body_a = getRigidBody(event.getBody(0));
auto* body_b = getRigidBody(event.getBody(1));
handleCollisionRemoved(event, body_a, body_b);
removeViscousSurfaceModifierAndCollision(event, body_a, body_b);
removeMassChangerModifier(event, body_a, body_b);
}
bool EntityContactListener::m15(RigidBody* body_a, RigidBody* body_b) {
if (body_a->isEntityMotionFlag4Off() && body_b->isEntityMotionFlag4Off() &&
(body_a->getMaxImpulse() >= 0 || body_b->getMaxImpulse() >= 0)) {
return true;
}
if (body_a->isEntityMotionFlag8On() || body_b->isEntityMotionFlag8On()) {
return true;
}
return false;
}
bool EntityContactListener::isObjectOrGroundOrNPCOrTree(const RigidBody& body) {
switch (body.getContactLayer().value()) {
case ContactLayer::EntityObject:
@ -45,6 +150,71 @@ bool EntityContactListener::isObjectOrGroundOrNPCOrTree(const hkpCdBody& cd_body
return isObjectOrGroundOrNPCOrTree(*body);
}
// TODO: rename
static bool unkLayerCheck(const RigidBody* body_a, const RigidBody* body_b, ContactLayer layer_a,
ContactLayer layer_b) {
if (layer_a.value() == ContactLayer::EntityPlayer ||
layer_a.value() == ContactLayer::EntityNPC) {
switch (layer_b.value()) {
case ContactLayer::EntityObject:
case ContactLayer::EntityGroundObject:
case ContactLayer::EntityTree:
if (!body_b->hasFlag(RigidBody::Flag::_400000))
return true;
break;
case ContactLayer::EntityPlayer:
case ContactLayer::EntityNPC:
return true;
default:
break;
}
}
if (layer_b.value() == ContactLayer::EntityPlayer ||
layer_b.value() == ContactLayer::EntityNPC) {
switch (layer_a.value()) {
case ContactLayer::EntityObject:
case ContactLayer::EntityGroundObject:
case ContactLayer::EntityTree:
if (!body_a->hasFlag(RigidBody::Flag::_400000))
return true;
break;
default:
break;
}
}
return false;
}
bool EntityContactListener::contactPointCallbackImpl(u32 ignored_layers_a, u32 ignored_layers_b,
RigidBody* body_a, RigidBody* body_b,
ContactLayer layer_a, ContactLayer layer_b,
const hkpContactPointEvent& event) {
if (shouldProcessEntityContact(ignored_layers_a, ignored_layers_b, layer_a, layer_b) ||
(_91 && unkLayerCheck(body_a, body_b, layer_a, layer_b))) {
disableContact(event);
if (event.m_type == hkpContactPointEvent::TYPE_MANIFOLD &&
(layer_a == ContactLayer::EntityWater || layer_b == ContactLayer::EntityWater)) {
clearCallbackDelay(event);
}
return false;
}
if (isContactDisabled(event)) {
auto* constraint = event.m_contactMgr->getConstraintInstance();
if (constraint == nullptr ||
constraint->getData()->getType() != hkpConstraintData::CONSTRAINT_TYPE_CONTACT ||
!(constraint->getUserData() & 0x10000)) {
// Clear the contact disabled flag.
enableContact(event);
}
}
return true;
}
void EntityContactListener::m11(const hkpContactPointEvent& event,
const RigidBodyCollisionMasks& masks_a,
const RigidBodyCollisionMasks& masks_b, RigidBody* body_a,
@ -70,4 +240,292 @@ void EntityContactListener::m11(const hkpContactPointEvent& event,
hk_point_properties->setRestitution(restitution);
}
KSYS_ALWAYS_INLINE static bool needsMagneMassScaling(const hkpCollisionEvent& event,
RigidBody* body_a, RigidBody* body_b) {
if (body_a->getMotionType() != MotionType::Dynamic ||
body_b->getMotionType() != MotionType::Dynamic) {
return false;
}
if (body_a->getEntityMotionAccessor() == nullptr ||
body_b->getEntityMotionAccessor() == nullptr) {
return false;
}
if (body_a->getEntityMotionAccessor()->getContactFlags().isOff(ContactFlag::_1) &&
body_b->getEntityMotionAccessor()->getContactFlags().isOff(ContactFlag::_1)) {
return false;
}
if (!hasEntityWithMotionFlag80(event))
return false;
return body_a->getMagneMassScalingFactor() >= 0 && body_b->getMagneMassScalingFactor() >= 0;
}
static void updateMotionAccessorFlagsForMagneMassScaling(RigidBody* body_a, RigidBody* body_b) {
// Set flag 1 and reset flag 2.
body_a->getEntityMotionAccessor()->getContactFlags().set(ContactFlag::_1);
body_b->getEntityMotionAccessor()->getContactFlags().set(ContactFlag::_1);
body_a->getEntityMotionAccessor()->getContactFlags().reset(ContactFlag::_2);
body_b->getEntityMotionAccessor()->getContactFlags().reset(ContactFlag::_2);
}
void EntityContactListener::setMagneMassScalingForContactIfNeeded(const hkpCollisionEvent& event,
RigidBody* body_a,
RigidBody* body_b) {
if (!System::instance()->getEntityContactListenerField90())
return;
if (!needsMagneMassScaling(event, body_a, body_b))
return;
updateMotionAccessorFlagsForMagneMassScaling(body_a, body_b);
setMagneMassScalingForContact(event, body_a, body_b);
}
void EntityContactListener::setImpulseScalingForTerrainContact(const hkpCollisionEvent& event,
RigidBody* body_a,
RigidBody* body_b) {
if (body_a->getType() != RigidBody::Type::TerrainHeightField &&
body_b->getType() != RigidBody::Type::TerrainHeightField) {
return;
}
auto* body1 = body_a->getType() == RigidBody::Type::TerrainHeightField ? body_a : body_b;
auto* body2 = body1 == body_a ? body_b : body_a;
if (body2->getType() != RigidBody::Type::CharacterController ||
int(body1->getContactLayer()) != ContactLayer::EntityGround) {
return;
}
auto* height_field_body = sead::DynamicCast<TerrainHeightFieldRigidBody>(body1);
if (!height_field_body || !height_field_body->getD8())
return;
[[maybe_unused]] auto* constraint = event.m_contactMgr->getConstraintInstance();
hkpResponseModifier::setImpulseScalingForContact(event.m_contactMgr, body_a->getHkBody(),
body_b->getHkBody(),
*event.getSimulationIsland(), 15.0, 25.0);
}
static bool removeViscousSurfaceModifier(const hkpCollisionEvent& event) {
constexpr auto type = hkpConstraintAtom::TYPE_MODIFIER_VISCOUS_SURFACE;
auto* constraint = event.m_contactMgr->getConstraintInstance();
if (!hkpWorldConstraintUtil::findModifier(constraint, type)) {
return false;
}
auto* island = event.getSimulationIsland();
hkpWorldConstraintUtil::removeAndDeleteModifier(constraint, *island, type);
if (constraint &&
constraint->getData()->getType() == hkpConstraintData::CONSTRAINT_TYPE_CONTACT) {
// TODO: add named constants for this flag?
constraint->m_userData &= ~1;
}
return true;
}
inline void EntityContactListener::removeViscousSurfaceModifierAndCollision(
const hkpCollisionEvent& event, RigidBody* body_a, RigidBody* body_b) {
if (!removeViscousSurfaceModifier(event))
return;
const auto update_contact_flags = [](RigidBody* body) {
if (!body->getEntityMotionAccessor()->getContactFlags().isOn(ContactFlag::_1)) {
return;
}
if (body->isEntityMotionFlag80On())
return;
body->getEntityMotionAccessor()->getContactFlags().reset(ContactFlag::_1);
body->getEntityMotionAccessor()->getContactFlags().set(ContactFlag::_2);
body->getEntityMotionAccessor()->getContactFlags().reset(ContactFlag::_4);
};
update_contact_flags(body_a);
update_contact_flags(body_b);
body_a->onCollisionRemoved();
body_b->onCollisionRemoved();
}
KSYS_ALWAYS_INLINE inline void
EntityContactListener::removeMassChangerModifier(const hkpCollisionEvent& event, RigidBody* body_a,
RigidBody* body_b) {
constexpr auto type = hkpConstraintAtom::TYPE_MODIFIER_MASS_CHANGER;
auto* constraint = event.m_contactMgr->getConstraintInstance();
if (hkpWorldConstraintUtil::findModifier(constraint, type)) {
auto* island = event.getSimulationIsland();
hkpWorldConstraintUtil::removeAndDeleteModifier(constraint, *island, type);
}
const auto a_is_water_and_b_not_charctrl = [](RigidBody* a, RigidBody* b) {
return a->getContactLayer() == ContactLayer::EntityWater &&
b->getType() != RigidBody::Type::CharacterController;
};
if (a_is_water_and_b_not_charctrl(body_a, body_b) ||
a_is_water_and_b_not_charctrl(body_b, body_a)) {
body_a->onCollisionRemoved();
body_b->onCollisionRemoved();
}
}
inline void EntityContactListener::setMagneMassScalingForContact(const hkpCollisionEvent& event,
RigidBody* body_a,
RigidBody* body_b) {
const auto factor_a = body_a->getMagneMassScalingFactor();
const auto factor_b = body_b->getMagneMassScalingFactor();
body_a->onCollisionAdded();
body_b->onCollisionAdded();
const auto mass_a = body_a->getMass();
const auto mass_b = body_b->getMass();
const auto* heavier_body = (mass_a < mass_b) ? body_b : body_a;
const auto* lighter_body = (mass_a < mass_b) ? body_a : body_b;
const auto heavier_factor = (mass_a < mass_b) ? factor_b : factor_a;
const auto lighter_factor = (mass_a < mass_b) ? factor_a : factor_b;
const auto effective_mass1 = lighter_body->getMass() * heavier_factor;
const auto effective_mass2 = heavier_body->getMass() * lighter_factor;
hkVector4f mass_ratio;
mass_ratio.setAll(effective_mass1 / effective_mass2);
hkpResponseModifier::setInvMassScalingForContact(event.m_contactMgr, lighter_body->getHkBody(),
*event.getSimulationIsland(), mass_ratio);
if (auto* constraint = event.m_contactMgr->getConstraintInstance()) {
if (constraint->getData()->getType() == hkpConstraintData::CONSTRAINT_TYPE_CONTACT)
constraint->m_userData |= 1;
}
}
static void updateMotionFlagsAtEndOfStep(const hkpCollisionEvent& event, RigidBody* body_a,
RigidBody* body_b) {
const auto update_flags1 = [](RigidBody* a, RigidBody* b) {
if (!a->getEntityMotionAccessor()->getContactFlags().isOn(ContactFlag::_2))
return false;
if (!b->getEntityMotionAccessor()->getContactFlags().isOn(ContactFlag::_4))
return false;
a->getEntityMotionAccessor()->getContactFlags().set(ContactFlag::_1);
a->getEntityMotionAccessor()->getContactFlags().reset(ContactFlag::_2);
a->getEntityMotionAccessor()->getContactFlags().set(ContactFlag::_4);
return true;
};
const auto update_flags2 = [](RigidBody* a, RigidBody* b) {
if (!a->getEntityMotionAccessor()->getContactFlags().isOn(ContactFlag::_2))
return false;
if (b->isEntityMotionFlag80On())
return false;
if (!b->getEntityMotionAccessor()->getContactFlags().isOn(ContactFlag::_1))
return false;
b->getEntityMotionAccessor()->getContactFlags().reset(ContactFlag::_1);
b->getEntityMotionAccessor()->getContactFlags().set(ContactFlag::_2);
return true;
};
const auto update_flags3 = [](RigidBody* a, RigidBody* b) {
if (!a->getEntityMotionAccessor()->getContactFlags().isOn(ContactFlag::_1))
return false;
if (!b->getEntityMotionAccessor()->getContactFlags().isOff(ContactFlag::_1))
return false;
b->getEntityMotionAccessor()->getContactFlags().set(ContactFlag::_1);
b->getEntityMotionAccessor()->getContactFlags().reset(ContactFlag::_2);
return true;
};
const auto update_flags4 = [](RigidBody* body) {
if (!body->getEntityMotionAccessor()->getContactFlags().isOn(ContactFlag::_4))
return false;
if (body->isEntityMotionFlag80On())
return false;
if (body->x_105())
return false;
body->getEntityMotionAccessor()->getContactFlags() = ContactFlag::_1;
return true;
};
bool updated1 = false;
updated1 |= update_flags1(body_a, body_b);
updated1 |= update_flags1(body_b, body_a);
if (!updated1) {
bool updated2 = false;
updated2 |= update_flags2(body_a, body_b);
updated2 |= update_flags2(body_b, body_a);
if (updated2) {
removeViscousSurfaceModifier(event);
} else {
update_flags3(body_a, body_b);
update_flags3(body_b, body_a);
}
}
update_flags4(body_a);
update_flags4(body_b);
}
// NON_MATCHING: branching (body_a->getEntityMotionAccessor() call not merged)
bool EntityContactListener::regularContactPointCallback(const hkpContactPointEvent& event,
RigidBody* body_a, RigidBody* body_b,
sead::SafeArray<u32, 2>*) {
if (event.m_type == hkpContactPointEvent::TYPE_MANIFOLD_AT_END_OF_STEP) {
auto* constraint = event.m_contactMgr->getConstraintInstance();
auto* modifier = hkpWorldConstraintUtil::findModifier(
constraint, hkpConstraintAtom::TYPE_MODIFIER_VISCOUS_SURFACE);
const bool field90 = System::instance()->getEntityContactListenerField90();
if (modifier && constraint->getUserData() & 1) {
clearCallbackDelay(event);
if (field90 && hasEntityWithMotionFlag80(event)) {
updateMotionFlagsAtEndOfStep(event, body_a, body_b);
} else {
body_a->getEntityMotionAccessor()->getContactFlags().makeAllZero();
body_b->getEntityMotionAccessor()->getContactFlags().makeAllZero();
removeViscousSurfaceModifier(event);
}
} else if (field90 && needsMagneMassScaling(event, body_a, body_b) &&
!shouldProcessEntityContact(body_a, body_b)) {
updateMotionAccessorFlagsForMagneMassScaling(body_a, body_b);
setMagneMassScalingForContact(event, body_a, body_b);
}
}
sead::SafeArray<u32, 2> material_masks;
bool result =
ContactListener::regularContactPointCallback(event, body_a, body_b, &material_masks);
if (event.m_contactPointProperties->m_flags & hkpContactPointProperties::CONTACT_IS_NEW &&
m15(body_a, body_b)) {
sead::Vector3f position, normal;
storeToVec3(&position, event.m_contactPoint->getPosition());
storeToVec3(&normal, event.m_contactPoint->getSeparatingNormal());
if (body_a->isEntityMotionFlag40On() || body_b->isEntityMotionFlag40On()) {
mMgr->x_26(body_a, body_b);
}
mMgr->x_27(body_a, body_b, position, normal, material_masks[0], material_masks[1]);
}
return result;
}
} // namespace ksys::phys

View File

@ -28,12 +28,27 @@ protected:
void m11(const hkpContactPointEvent& event, const RigidBodyCollisionMasks& masks_a,
const RigidBodyCollisionMasks& masks_b, RigidBody* body_a, RigidBody* body_b) override;
bool
regularContactPointCallback(const hkpContactPointEvent& event, RigidBody* body_a,
RigidBody* body_b,
sead::SafeArray<MaterialMaskData, 2>* out_material_masks) override;
bool regularContactPointCallback(const hkpContactPointEvent& event, RigidBody* body_a,
RigidBody* body_b,
sead::SafeArray<u32, 2>* out_material_masks) override;
u32 m15() override;
bool m15(RigidBody* body_a, RigidBody* body_b) override;
private:
void setMagneMassScalingForContactIfNeeded(const hkpCollisionEvent& event, RigidBody* body_a,
RigidBody* body_b);
void setImpulseScalingForTerrainContact(const hkpCollisionEvent& event, RigidBody* body_a,
RigidBody* body_b);
void removeViscousSurfaceModifierAndCollision(const hkpCollisionEvent& event, RigidBody* body_a,
RigidBody* body_b);
void removeMassChangerModifier(const hkpCollisionEvent& event, RigidBody* body_a,
RigidBody* body_b);
void setMagneMassScalingForContact(const hkpCollisionEvent& event, RigidBody* body_a,
RigidBody* body_b);
};
} // namespace ksys::phys

View File

@ -50,8 +50,8 @@ EntityGroupFilter::EntityGroupFilter(ContactLayer::ValueType first, ContactLayer
EntityGroupFilter::~EntityGroupFilter() = default;
void EntityGroupFilter::doInit_(sead::Heap* heap) {
// Enable all collisions by default.
mMasks.fill(0xffffffff);
// Allow any layer pairs to be ignored by a rigid body by default.
mLayersThatCanBeIgnored.fill(0xffffffff);
}
hkBool EntityGroupFilter::shouldHandleGroundCollision(u32 infoA, u32 infoB,

View File

@ -41,7 +41,7 @@ public:
hkBool isCollisionEnabled(const hkpWorldRayCastInput& inputA,
const hkpCollidable& collidableB) const override;
bool m2(ContactLayer layerA, ContactLayer layerB) override;
bool shouldContactNeverBeIgnored(ContactLayer layerA, ContactLayer layerB) override;
u32 makeCollisionFilterInfo(ContactLayer layer, GroundHit ground_hit) override;
ContactLayer getCollisionFilterInfoLayer(u32 info) override;
u32 makeQueryCollisionMask(u32 layer_mask, GroundHit ground_hit, bool unk) override;
@ -78,7 +78,10 @@ private:
int getFreeListIndex(const SystemGroupHandler* handler) override;
void doInit_(sead::Heap* heap) override;
sead::SafeArray<u32, ContactLayer::size()> mMasks;
/// A ContactLayer::size() x ContactLayer::size() matrix such that M[i][j] indicates
/// whether contact between layers i and layers j can be ignored.
/// \see EntityContactListener and shouldContactNeverBeIgnored
sead::SafeArray<u32, ContactLayer::size()> mLayersThatCanBeIgnored;
};
void receiverMaskEnableLayer(SensorCollisionMask* mask, ContactLayer layer);
@ -143,8 +146,9 @@ inline bool EntitySystemGroupHandler::m8() {
return getIndex() > 0 && getIndex() < 0x400;
}
inline bool EntityGroupFilter::m2(ContactLayer layerA, ContactLayer layerB) {
return (mMasks[layerA.value()] & (1 << layerB.value())) == 0;
inline bool EntityGroupFilter::shouldContactNeverBeIgnored(ContactLayer layerA,
ContactLayer layerB) {
return (mLayersThatCanBeIgnored[layerA.value()] & (1 << layerB.value())) == 0;
}
inline u32 EntityGroupFilter::makeCollisionFilterInfo(ContactLayer layer, GroundHit ground_hit) {
@ -185,7 +189,7 @@ inline const char* EntityGroupFilter::getCollisionFilterInfoLayerText(u32 info)
}
inline void EntityGroupFilter::setLayerCustomMask(ContactLayer layer, u32 mask) {
mMasks[layer] = mask;
mLayersThatCanBeIgnored[layer] = mask;
}
inline u32 EntityGroupFilter::getCollisionFilterInfoGroupHandlerIdx(u32 info) {

View File

@ -75,7 +75,11 @@ public:
m_collisionLookupTable[layer - getLayerFirst()] = mask;
}
virtual bool m2(ContactLayer layerA, ContactLayer layerB) { return true; }
/// Indicates whether contact between layerA and layerB should never be ignored,
/// even if the corresponding rigid bodies are configured to ignore each other's layer.
virtual bool shouldContactNeverBeIgnored(ContactLayer layerA, ContactLayer layerB) {
return true;
}
/// Make a collision filter mask with the specified layer and ground hit type.
virtual u32 makeCollisionFilterInfo(ContactLayer layer, GroundHit ground_hit) = 0;

View File

@ -77,6 +77,12 @@ public:
void lockWorld(ContactLayerType type, void* a = nullptr, int b = 0, bool c = false);
void unlockWorld(ContactLayerType type, void* a = nullptr, int b = 0, bool c = false);
// TODO: rename
// 0x0000007101216c60
void setEntityContactListenerField90(bool value);
// 0x0000007101216c74
bool getEntityContactListenerField90() const;
// 0x0000007101216cec
sead::Heap* getPhysicsTempHeap(LowPriority low_priority) const;

View File

@ -101,16 +101,20 @@ inline u32 getShapeKeyOrMinus1(const u32* shape_key) {
return shape_key ? *shape_key : u32(-1);
}
inline const hkpEntity* getHkpEntity(const hkpCollidable& collidable) {
if (collidable.getType() != hkpWorldObject::BroadPhaseType::BROAD_PHASE_ENTITY)
return nullptr;
return static_cast<const hkpEntity*>(collidable.getOwner());
}
inline RigidBody* getRigidBody(const hkpEntity* entity) {
// This needs to be kept in sync with the RigidBody constructor!
return reinterpret_cast<RigidBody*>(entity->getUserData());
}
inline RigidBody* getRigidBody(const hkpCollidable& collidable) {
if (collidable.getType() != hkpWorldObject::BroadPhaseType::BROAD_PHASE_ENTITY)
return nullptr;
auto* entity = static_cast<const hkpEntity*>(collidable.getOwner());
auto* entity = getHkpEntity(collidable);
if (!entity)
return nullptr;