ksys/phys: Add more EntityGroupFilter functions

This commit is contained in:
Léo Lam 2022-02-15 00:06:09 +01:00
parent b3b97a93aa
commit c32557b793
No known key found for this signature in database
GPG Key ID: 0DF30F9081000741
10 changed files with 480 additions and 74 deletions

View File

@ -83797,17 +83797,17 @@ Address,Quality,Size,Name
0x0000007100fb503c,O,000096,_ZThn32_N4ksys4phys17EntityGroupFilterD0Ev
0x0000007100fb509c,O,000096,_ZThn40_N4ksys4phys17EntityGroupFilterD0Ev
0x0000007100fb50fc,O,000032,_ZN4ksys4phys17EntityGroupFilter7doInit_EPN4sead4HeapE
0x0000007100fb511c,U,001440,phys::EntityGroupFilter::isCollisionEnabled
0x0000007100fb511c,m,001440,_ZNK4ksys4phys17EntityGroupFilter24testCollisionForEntitiesEjj
0x0000007100fb56bc,O,000268,_ZNK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK13hkpCollidableS4_
0x0000007100fb57c8,O,000028,_ZThn16_NK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK13hkpCollidableS4_
0x0000007100fb57e4,O,000176,_ZNK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK17hkpCollisionInputRK9hkpCdBodyS7_RK17hkpShapeContainerSA_jj
0x0000007100fb5894,O,000176,_ZThn24_NK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK17hkpCollisionInputRK9hkpCdBodyS7_RK17hkpShapeContainerSA_jj
0x0000007100fb5944,O,000304,_ZNK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK17hkpCollisionInputRK9hkpCdBodyS7_RK17hkpShapeContainerj
0x0000007100fb5a74,O,000028,_ZThn24_NK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK17hkpCollisionInputRK9hkpCdBodyS7_RK17hkpShapeContainerj
0x0000007100fb5a90,U,000284,phys::EntityGroupFilter::isCollisionEnabled__3
0x0000007100fb5bac,U,000284,
0x0000007100fb5cc8,U,000256,phys::EntityGroupFilter::isCollisionEnabled__4
0x0000007100fb5dc8,U,000028,
0x0000007100fb5a90,O,000284,_ZNK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK20hkpShapeRayCastInputRK17hkpShapeContainerj
0x0000007100fb5bac,O,000284,_ZThn32_NK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK20hkpShapeRayCastInputRK17hkpShapeContainerj
0x0000007100fb5cc8,O,000256,_ZNK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK20hkpWorldRayCastInputRK13hkpCollidable
0x0000007100fb5dc8,O,000028,_ZThn40_NK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK20hkpWorldRayCastInputRK13hkpCollidable
0x0000007100fb5de4,O,000192,_ZN4ksys4phys17EntityGroupFilter30doInitSystemGroupHandlerLists_EPN4sead4HeapE
0x0000007100fb5ea4,O,000016,_ZN4ksys4phys17EntityGroupFilter16getFreeListIndexEPKNS0_18SystemGroupHandlerE
0x0000007100fb5eb4,O,000036,_ZN4ksys4phys21orEntityGroundHitMaskEjNS0_9GroundHitE
@ -83815,29 +83815,29 @@ Address,Quality,Size,Name
0x0000007100fb5f14,O,000032,_ZN4ksys4phys23makeEntityGroundHitMaskENS0_12ContactLayerEj
0x0000007100fb5f34,O,000068,_ZN4ksys4phys23makeEntityCollisionMaskENS0_12ContactLayerEj
0x0000007100fb5f78,O,000036,_ZN4ksys4phys31setEntityCollisionMaskGroundHitENS0_9GroundHitEj
0x0000007100fb5f9c,U,000084,EntitySystemGroupHandler::m5
0x0000007100fb5ff0,U,000048,EntitySystemGroupHandler::m6
0x0000007100fb6020,U,000040,EntitySystemGroupHandler::m7
0x0000007100fb6048,U,000020,EntitySystemGroupHandler::m8
0x0000007100fb5f9c,O,000084,_ZN4ksys4phys24EntitySystemGroupHandler23makeCollisionFilterInfoEjNS0_12ContactLayerENS0_9GroundHitE
0x0000007100fb5ff0,O,000048,_ZN4ksys4phys24EntitySystemGroupHandler22makeQueryCollisionMaskEjNS0_9GroundHitEb
0x0000007100fb6020,O,000040,_ZN4ksys4phys24EntitySystemGroupHandler30makeRagdollCollisionFilterInfoENS0_9GroundHitE
0x0000007100fb6048,O,000020,_ZN4ksys4phys24EntitySystemGroupHandler2m8Ev
0x0000007100fb605c,O,000112,_ZNK4ksys4phys18SystemGroupHandler27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE
0x0000007100fb60cc,O,000092,_ZNK4ksys4phys18SystemGroupHandler18getRuntimeTypeInfoEv
0x0000007100fb6128,O,000004,_ZN4ksys4phys18SystemGroupHandlerD2Ev
0x0000007100fb612c,O,000004,_ZN4ksys4phys18SystemGroupHandlerD0Ev
0x0000007100fb612c,O,000004,_ZN4ksys4phys24EntitySystemGroupHandlerD0Ev
0x0000007100fb6130,O,000004,_ZN18hkpCollisionFilter4initEP8hkpWorld
0x0000007100fb6134,O,000008,_ZN14hkpGroupFilter11dummyUnusedEv
0x0000007100fb613c,O,000204,_ZNK4ksys4phys17EntityGroupFilter27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE
0x0000007100fb6208,O,000092,_ZNK4ksys4phys17EntityGroupFilter18getRuntimeTypeInfoEv
0x0000007100fb6264,U,000044,phys::EntityGroupFilter::m2
0x0000007100fb6290,U,000028,phys::EntityGroupFilter::m3
0x0000007100fb62ac,U,000020,phys::EntityGroupFilter::m4
0x0000007100fb62c0,U,000028,phys::EntityGroupFilter::m5
0x0000007100fb62dc,U,000008,phys::EntityGroupFilter::m6
0x0000007100fb62e4,U,000040,phys::EntityGroupFilter::m7
0x0000007100fb630c,U,000048,phys::EntityGroupFilter::m8_GetStringGroundHitMaskModeOrSensorText
0x0000007100fb6264,O,000044,_ZN4ksys4phys17EntityGroupFilter2m2ENS0_12ContactLayerES2_
0x0000007100fb6290,O,000028,_ZN4ksys4phys17EntityGroupFilter23makeCollisionFilterInfoENS0_12ContactLayerENS0_9GroundHitE
0x0000007100fb62ac,O,000020,_ZN4ksys4phys17EntityGroupFilter27getCollisionFilterInfoLayerEj
0x0000007100fb62c0,O,000028,_ZN4ksys4phys17EntityGroupFilter22makeQueryCollisionMaskEjNS0_9GroundHitEb
0x0000007100fb62dc,O,000008,_ZN4ksys4phys17EntityGroupFilter30getQueryCollisionMaskGroundHitEj
0x0000007100fb62e4,O,000040,_ZN4ksys4phys17EntityGroupFilter39getCollisionFilterInfoLayerAndGroundHitEjPNS0_12ContactLayerEPNS0_9GroundHitE
0x0000007100fb630c,O,000048,_ZN4ksys4phys17EntityGroupFilter31getCollisionFilterInfoLayerTextEj
0x0000007100fb633c,O,000036,_ZN4ksys4phys17EntityGroupFilter18setLayerCustomMaskENS0_12ContactLayerEj
0x0000007100fb6360,U,000008,phys::EntityGroupFilter::m10
0x0000007100fb6368,U,000044,phys::EntityGroupFilter::m14
0x0000007100fb6394,U,000028,phys::EntityGroupFilter::m15
0x0000007100fb6360,O,000008,_ZN4ksys4phys17EntityGroupFilter37getCollisionFilterInfoGroupHandlerIdxEj
0x0000007100fb6368,O,000044,_ZN4ksys4phys17EntityGroupFilter23makeCollisionFilterInfoENS0_12ContactLayerENS0_9GroundHitEjj
0x0000007100fb6394,O,000028,_ZN4ksys4phys17EntityGroupFilter34setEntityLayerCollisionEnabledMaskENS0_12ContactLayerEj
0x0000007100fb63b0,O,000140,_ZNK4sead15RuntimeTypeInfo6DeriveIN4ksys4phys11GroupFilterEE9isDerivedEPKNS0_9InterfaceE
0x0000007100fb643c,U,000108,phys::makeEntityContactListener
0x0000007100fb64a8,U,000004,j_ksys::phys::ContactListener::dtor
@ -93391,7 +93391,7 @@ Address,Quality,Size,Name
0x0000007101213c68,O,000148,_ZN4ksys4phys11GroupFilter7destroyEv
0x0000007101213cfc,O,000160,_ZN4ksys4phys11GroupFilter21addSystemGroupHandlerEi
0x0000007101213d9c,O,000148,_ZN4ksys4phys11GroupFilter24removeSystemGroupHandlerEPNS0_18SystemGroupHandlerE
0x0000007101213e30,O,000008,_ZN4ksys4phys18SystemGroupHandler2m7Ev
0x0000007101213e30,O,000008,_ZN4ksys4phys18SystemGroupHandler30makeRagdollCollisionFilterInfoENS0_9GroundHitE
0x0000007101213e38,O,000024,_ZN4ksys4phys18SystemGroupHandler10removeThisEv
0x0000007101213e50,O,000112,_ZNK4ksys4phys11GroupFilter27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE
0x0000007101213ec0,O,000092,_ZNK4ksys4phys11GroupFilter18getRuntimeTypeInfoEv

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

View File

@ -63,6 +63,7 @@ public:
inline hkUint32 getCollisionFilterInfo() const;
inline void setCollisionFilterInfo(hkUint32 info);
/// @see hkpWorldObject::BroadPhaseType
inline int getType() const;
protected:

View File

@ -2,8 +2,8 @@
#include <Havok/Common/Base/Types/hkBaseTypes.h>
class hkpWorldRayCastInput;
class hkpCollidable;
struct hkpWorldRayCastInput;
class hkpRayCollidableFilter {
public:

View File

@ -602,8 +602,8 @@ void RigidBody::enableGroundCollision(bool enabled) {
const auto current_info = getEntityCollisionFilterInfo();
auto info = current_info;
info.unk5 = false;
info.no_ground_collision.SetBit(!enabled);
info.ground_col_mode =
enabled ? GroundCollisionMode::Normal : GroundCollisionMode::IgnoreGround;
if (current_info != info)
setCollisionFilterInfo(info.raw);
}
@ -615,9 +615,8 @@ bool RigidBody::isGroundCollisionEnabled() const {
const auto info = getEntityCollisionFilterInfo();
bool enabled = false;
enabled |= info.unk5;
enabled |= info.ground_col_mode != GroundCollisionMode::IgnoreGround;
enabled |= info.unk30;
enabled |= !info.no_ground_collision;
return enabled;
}
@ -630,7 +629,7 @@ void RigidBody::enableWaterCollision(bool enabled) {
const auto current_info = getEntityCollisionFilterInfo();
auto info = current_info;
info.no_water_collision = !enabled;
info.water_col_mode = enabled ? WaterCollisionMode::Normal : WaterCollisionMode::IgnoreWater;
if (current_info != info)
setCollisionFilterInfo(info.raw);
}
@ -644,7 +643,7 @@ bool RigidBody::isWaterCollisionEnabled() const {
bool enabled = false;
// unk30 enables all collisions?
enabled |= info.unk30;
enabled |= !info.no_water_collision;
enabled |= info.water_col_mode != WaterCollisionMode::IgnoreWater;
return enabled;
}

View File

@ -2,11 +2,15 @@
#include <Havok/Physics2012/Collide/Agent/Collidable/hkpCollidable.h>
#include <Havok/Physics2012/Collide/Agent/hkpCollisionInput.h>
#include <Havok/Physics2012/Collide/Dispatch/hkpCollisionDispatcher.h>
#include <Havok/Physics2012/Collide/Query/CastUtil/hkpWorldRayCastInput.h>
#include <Havok/Physics2012/Collide/Shape/Compound/Collection/hkpShapeCollection.h>
#include <Havok/Physics2012/Collide/Shape/Compound/Tree/hkpBvTreeShape.h>
#include <Havok/Physics2012/Collide/Shape/Query/hkpShapeRayCastInput.h>
#include <Havok/Physics2012/Collide/Shape/hkpShapeContainer.h>
#include <Havok/Physics2012/Dynamics/World/hkpWorldObject.h>
#include <heap/seadHeap.h>
#include "Havok/Physics2012/Dynamics/Entity/hkpEntity.h"
#include "KingSystem/Physics/RigidBody/physRigidBody.h"
#include "KingSystem/Physics/System/physContactMgr.h"
#include "KingSystem/Physics/System/physSystem.h"
#include "KingSystem/Utils/BitField.h"
@ -49,16 +53,170 @@ void EntityGroupFilter::doInit_(sead::Heap* heap) {
mMasks.fill(0xffffffff);
}
hkBool EntityGroupFilter::isCollisionEnabledPhantom(u32 infoPhantom, u32 infoB) const {
hkBool EntityGroupFilter::shouldHandleGroundCollision(u32 infoA, u32 infoB,
ContactLayer::ValueType layerA,
ContactLayer::ValueType layerB) const {
const EntityCollisionFilterInfo a{infoA};
const EntityCollisionFilterInfo b{infoB};
if (EntityCollisionFilterInfo(infoA | infoB).ground_col_mode != GroundCollisionMode::Normal) {
if (a.ground_col_mode != GroundCollisionMode::Normal) {
bool ground = isEntityGroundLayer(layerB);
if (a.ground_col_mode == GroundCollisionMode::IgnoreNonGround && !ground)
return false;
if (a.ground_col_mode == GroundCollisionMode::IgnoreGround && ground)
return false;
}
if (b.ground_col_mode != GroundCollisionMode::Normal) {
bool ground = isEntityGroundLayer(layerA);
if (b.ground_col_mode == GroundCollisionMode::IgnoreNonGround && !ground)
return false;
if (b.ground_col_mode == GroundCollisionMode::IgnoreGround && ground)
return false;
}
}
return true;
}
hkBool EntityGroupFilter::shouldHandleWaterCollision(u32 infoA, u32 infoB,
ContactLayer::ValueType layerA,
ContactLayer::ValueType layerB) const {
const EntityCollisionFilterInfo a{infoA};
const EntityCollisionFilterInfo b{infoB};
if (EntityCollisionFilterInfo(infoA | infoB).water_col_mode != WaterCollisionMode::Normal) {
if (a.water_col_mode == WaterCollisionMode::IgnoreWater &&
layerB == ContactLayer::EntityWater) {
return false;
}
if (b.water_col_mode == WaterCollisionMode::IgnoreWater &&
layerA == ContactLayer::EntityWater) {
return false;
}
}
return true;
}
// XXX: find a better name
static bool testHandler(u32 idx) {
return idx != 0 && idx <= 15;
}
// NON_MATCHING: deduplicated branch: `return a.data.query_custom_receiver_layer_mask & (1 << ...)`
hkBool EntityGroupFilter::testCollisionForEntities(u32 infoA, u32 infoB) const {
if (mInhibitCollisions)
return false;
// TODO: figure out what kind of mask infoPhantom is. Receiver/sensor mask?
// RigidBodyParam::getParams and ContactInfoTable seem to manipulate similar looking masks.
const EntityCollisionFilterInfo a{infoA};
const EntityCollisionFilterInfo b{infoB};
constexpr auto GroupHandlerIdxMask = decltype(a.group_handler_index)::GetMask();
constexpr auto GroupHandlerIdxShift = decltype(a.group_handler_index)::StartBit();
if (!EntityCollisionFilterInfo(infoA | infoB).is_ground_hit_mask) {
if (a.unk30 && b.unk30) {
if (((infoA ^ infoB) & GroupHandlerIdxMask) != 0) {
if (testHandler(a.group_handler_index) || testHandler(b.group_handler_index))
return false;
} else if ((infoA & GroupHandlerIdxMask) >> GroupHandlerIdxShift != 0) {
if (a.data.unk5 == b.data.unk10 || b.data.unk5 == a.data.unk10)
return false;
}
return true;
}
const auto layerA = static_cast<ContactLayer::ValueType>(a.data.layer.Value());
const auto layerB = static_cast<ContactLayer::ValueType>(b.data.layer.Value());
if (layerA != ContactLayer::EntityQueryCustomReceiver &&
layerB != ContactLayer::EntityQueryCustomReceiver) {
if (!a.unk30 && !b.unk30) {
if (!shouldHandleGroundCollision(infoA, infoB, layerA, layerB))
return false;
if (!shouldHandleWaterCollision(infoA, infoB, layerA, layerB))
return false;
}
if (((infoA ^ infoB) & GroupHandlerIdxMask) != 0) {
if (testHandler(a.group_handler_index) || testHandler(b.group_handler_index))
return false;
} else if (((infoA & GroupHandlerIdxMask) >> GroupHandlerIdxShift) > 15) {
return false;
}
return testLayerCollision(layerA, layerB);
}
if (layerA == ContactLayer::EntityQueryCustomReceiver &&
layerB == ContactLayer::EntityQueryCustomReceiver) {
return false;
}
if (layerA == ContactLayer::EntityQueryCustomReceiver)
return a.data.query_custom_receiver_layer_mask & (1 << layerB);
else
return b.data.query_custom_receiver_layer_mask & (1 << layerA);
}
if (a.is_ground_hit_mask && b.is_ground_hit_mask) {
const auto layerA = static_cast<ContactLayer::ValueType>(a.ground_hit.layer.Value());
const auto layerB = static_cast<ContactLayer::ValueType>(b.ground_hit.layer.Value());
if (!shouldHandleGroundCollision(infoA, infoB, layerA, layerB))
return false;
if (!shouldHandleWaterCollision(infoA, infoB, layerA, layerB))
return false;
if (!testLayerCollision(layerA, layerB))
return false;
return !a.ground_hit.unk23 && !b.ground_hit.unk23;
}
EntityCollisionFilterInfo entity_mask, ground_hit_mask;
if (a.is_ground_hit_mask && !b.is_ground_hit_mask) {
const auto layerA = static_cast<ContactLayer::ValueType>(a.ground_hit.layer.Value());
const auto layerB = static_cast<ContactLayer::ValueType>(b.data.layer.Value());
entity_mask = b;
ground_hit_mask = a;
if (layerB == ContactLayer::EntityQueryCustomReceiver)
return b.data.query_custom_receiver_layer_mask & (1 << layerA);
if (!b.unk30 && !shouldHandleGroundCollision(infoA, infoB, layerA, layerB))
return false;
if (!b.unk30 && !shouldHandleWaterCollision(infoA, infoB, layerA, layerB))
return false;
if (!testLayerCollision(layerA, layerB))
return false;
} else /* A entity, B ground hit */ {
const auto layerA = static_cast<ContactLayer::ValueType>(a.data.layer.Value());
const auto layerB = static_cast<ContactLayer::ValueType>(b.ground_hit.layer.Value());
entity_mask = a;
ground_hit_mask = b;
if (layerA == ContactLayer::EntityQueryCustomReceiver)
return a.data.query_custom_receiver_layer_mask & (1 << layerB);
if (!a.unk30 && !shouldHandleGroundCollision(infoA, infoB, layerA, layerB))
return false;
if (!a.unk30 && !shouldHandleWaterCollision(infoA, infoB, layerA, layerB))
return false;
if (!testLayerCollision(layerB, layerA))
return false;
}
return !(ground_hit_mask.ground_hit.ground_hit_types & (1 << entity_mask.data.ground_hit));
}
hkBool EntityGroupFilter::testCollisionForPhantom(u32 infoPhantom, u32 infoB) const {
if (mInhibitCollisions)
return false;
RayCastCollisionMask infoPhantomData{infoPhantom};
const EntityCollisionFilterInfo info{infoB};
if (info.is_ground_hit_mask)
return infoPhantom & (1 << info.ground_hit.getLayer());
return (infoPhantom & (1 << info.data.layer)) & 0x1ffff;
return infoPhantomData.raw & (1 << info.ground_hit.getLayer());
return infoPhantomData.layer_mask & (1 << info.data.layer);
}
hkBool EntityGroupFilter::isCollisionEnabled(const hkpCollidable& a, const hkpCollidable& b) const {
@ -69,19 +227,19 @@ hkBool EntityGroupFilter::isCollisionEnabled(const hkpCollidable& a, const hkpCo
if (a.getType() == hkpWorldObject::BROAD_PHASE_PHANTOM) {
if (a.getShape() != nullptr)
return isCollisionEnabled(a.getCollisionFilterInfo(), b.getCollisionFilterInfo());
return testCollisionForEntities(a.getCollisionFilterInfo(), b.getCollisionFilterInfo());
return isCollisionEnabledPhantom(a.getCollisionFilterInfo(), b.getCollisionFilterInfo());
return testCollisionForPhantom(a.getCollisionFilterInfo(), b.getCollisionFilterInfo());
}
if (b.getType() == hkpWorldObject::BROAD_PHASE_PHANTOM) {
if (b.getShape() != nullptr)
return isCollisionEnabled(a.getCollisionFilterInfo(), b.getCollisionFilterInfo());
return testCollisionForEntities(a.getCollisionFilterInfo(), b.getCollisionFilterInfo());
return isCollisionEnabledPhantom(b.getCollisionFilterInfo(), a.getCollisionFilterInfo());
return testCollisionForPhantom(b.getCollisionFilterInfo(), a.getCollisionFilterInfo());
}
return isCollisionEnabled(a.getCollisionFilterInfo(), b.getCollisionFilterInfo());
return testCollisionForEntities(a.getCollisionFilterInfo(), b.getCollisionFilterInfo());
}
hkBool EntityGroupFilter::isCollisionEnabled(const hkpCollisionInput& input,
@ -98,7 +256,7 @@ hkBool EntityGroupFilter::isCollisionEnabled(const hkpCollisionInput& input,
if (infoB == 0xffffffff)
infoB = collectionBodyB.getRootCollidable()->getCollisionFilterInfo();
return isCollisionEnabled(infoA, infoB);
return testCollisionForEntities(infoA, infoB);
}
hkBool EntityGroupFilter::isCollisionEnabled(const hkpCollisionInput& input, const hkpCdBody& a,
@ -150,7 +308,72 @@ hkBool EntityGroupFilter::isCollisionEnabled(const hkpCollisionInput& input, con
}
end:
return isCollisionEnabled(infoA, infoB);
return testCollisionForEntities(infoA, infoB);
}
static hkBool
checkCollisionWithGroundHitMask(EntityCollisionFilterInfo::GroundHitMask ground_hit_mask,
RayCastCollisionMask ray_cast) {
if (!(ray_cast.layer_mask & (1 << ground_hit_mask.getLayer())))
return false;
if (ground_hit_mask.unk & ray_cast.unk)
return false;
if (ground_hit_mask.ground_hit_types & (1 << ray_cast.ground_hit_type))
return false;
return true;
}
hkBool EntityGroupFilter::testCollisionForRayCasting(u32 infoRayCast, u32 info) const {
if (mInhibitCollisions)
return false;
RayCastCollisionMask a{infoRayCast};
EntityCollisionFilterInfo b{info};
if (b.is_ground_hit_mask)
return checkCollisionWithGroundHitMask(b.ground_hit, a);
const u32 bHandlerIdx = b.group_handler_index;
const u32 aHandlerIdx = a.group_handler_index;
if (aHandlerIdx == bHandlerIdx) {
if (bHandlerIdx > 15)
return false;
return a.layer_mask & (1 << b.data.layer);
}
if (testHandler(aHandlerIdx) || testHandler(bHandlerIdx))
return false;
return a.layer_mask & (1 << b.data.layer);
}
KSYS_ALWAYS_INLINE hkBool EntityGroupFilter::isCollisionEnabled(const hkpShapeRayCastInput& aInput,
const hkpShapeContainer& bContainer,
hkpShapeKey bKey) const {
u32 bInfo = bContainer.getCollisionFilterInfo(bKey);
if (bInfo == 0)
return true;
if (bInfo == 0xffffffff)
bInfo = aInput.m_collidable->getCollisionFilterInfo();
return testCollisionForRayCasting(aInput.m_filterInfo, bInfo);
}
hkBool EntityGroupFilter::isCollisionEnabled(const hkpWorldRayCastInput& inputA,
const hkpCollidable& collidableB) const {
if (collidableB.getType() == hkpWorldObject::BROAD_PHASE_ENTITY) {
auto* entity = static_cast<const hkpEntity*>(collidableB.getOwner());
auto* body = entity ? reinterpret_cast<RigidBody*>(entity->getUserData()) : nullptr;
if (body && body->hasFlag(RigidBody::Flag::_200))
return false;
}
return testCollisionForRayCasting(inputA.m_filterInfo, collidableB.getCollisionFilterInfo());
}
void EntityGroupFilter::doInitSystemGroupHandlerLists_(sead::Heap* heap) {

View File

@ -13,7 +13,8 @@ public:
explicit EntitySystemGroupHandler(int i) : SystemGroupHandler(i, ContactLayerType::Entity) {}
u32 makeCollisionFilterInfo(u32 info, ContactLayer layer, GroundHit ground_hit) override;
u32 m6() override;
u32 makeQueryCollisionMask(u32 layer_mask, GroundHit ground_hit, bool unk) override;
u32 makeRagdollCollisionFilterInfo(GroundHit ground_hit) override;
bool m8() override;
};
@ -40,27 +41,42 @@ public:
hkBool isCollisionEnabled(const hkpWorldRayCastInput& inputA,
const hkpCollidable& collidableB) const override;
bool m2() override { return GroupFilter::m2(); }
void m3() override {}
void m4() override {}
void m5() override {}
void m6() override {}
void m7() override {}
void m8() override {}
bool m2(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;
GroundHit getQueryCollisionMaskGroundHit(u32 info) override;
void getCollisionFilterInfoLayerAndGroundHit(u32 info, ContactLayer* layer,
GroundHit* ground_hit) override;
const char* getCollisionFilterInfoLayerText(u32 info) override;
void setLayerCustomMask(ContactLayer layer, u32 mask) override;
u32 getCollisionFilterInfoGroupHandlerIdx(u32 info) override;
void setLayerCustomMask(ContactLayer layer, u32 mask) override { mMasks[layer] = mask; }
void m10() override {}
virtual u32 makeCollisionFilterInfo(ContactLayer layer, GroundHit ground_hit, u32 unk5,
u32 unk10);
/// @param layer An entity layer
virtual void setEntityLayerCollisionEnabledMask(ContactLayer layer, u32 mask);
private:
hkBool isCollisionEnabled(u32 infoA, u32 infoB) const;
hkBool isCollisionEnabledPhantom(u32 infoPhantom, u32 infoB) const;
/// Checks whether two entities are colliding.
hkBool testCollisionForEntities(u32 infoA, u32 gh_mask) const;
/// Checks whether a phantom and an entity are colliding with each other.
hkBool testCollisionForPhantom(u32 infoPhantom, u32 infoB) const;
/// Checks whether a ray cast and an entity are colliding with each other.
hkBool testCollisionForRayCasting(u32 infoRayCast, u32 info) const;
hkBool shouldHandleGroundCollision(u32 infoA, u32 infoB, ContactLayer::ValueType layerA,
ContactLayer::ValueType layerB) const;
hkBool shouldHandleWaterCollision(u32 infoA, u32 infoB, ContactLayer::ValueType layerA,
ContactLayer::ValueType layerB) const;
hkBool testLayerCollision(ContactLayer::ValueType a, ContactLayer::ValueType b) const {
return m_collisionLookupTable[a] & (1 << b);
}
void doInitSystemGroupHandlerLists_(sead::Heap* heap) override;
int getFreeListIndex(const SystemGroupHandler* handler) override;
void doInit_(sead::Heap* heap) override;
virtual void m14();
virtual void m15();
sead::SafeArray<u32, ContactLayer::size()> mMasks;
};
@ -84,4 +100,111 @@ u32 makeEntityCollisionMask(ContactLayer layer, u32 mask);
/// Updates the collision mask with the specified ground hit type (*not* mask).
u32 setEntityCollisionMaskGroundHit(GroundHit ground_hit, u32 mask);
inline u32 EntitySystemGroupHandler::makeCollisionFilterInfo(u32 info, ContactLayer layer,
GroundHit ground_hit) {
const EntityCollisionFilterInfo current_info{info};
EntityCollisionFilterInfo result;
if (layer == ContactLayer::EntityRagdoll) {
result.data.layer.Init(layer);
result.data.unk5.Init(current_info.data.unk5);
result.data.unk10.Init(current_info.data.unk10);
result.group_handler_index.Init(getIndex());
result.data.ground_hit.Init(ground_hit);
result.unk30 = true;
} else {
result.data.layer.Init(layer);
result.ground_col_mode.Init(current_info.ground_col_mode);
result.group_handler_index.Init(getIndex());
result.data.ground_hit.Init(ground_hit);
}
return result.raw;
}
inline u32 EntitySystemGroupHandler::makeQueryCollisionMask(u32 layer_mask, GroundHit ground_hit,
bool unk) {
RayCastCollisionMask mask;
mask.layer_mask = layer_mask;
mask.group_handler_index.Init(getIndex());
mask.ground_hit_type.Init(static_cast<GroundHit::ValueType>(int(ground_hit)));
mask.unk.SetBit(unk);
return mask.raw;
}
inline u32 EntitySystemGroupHandler::makeRagdollCollisionFilterInfo(GroundHit ground_hit) {
EntityCollisionFilterInfo info;
info.data.layer.Init(ContactLayer::EntityRagdoll);
info.group_handler_index.Init(getIndex());
info.data.ground_hit.Init(ground_hit);
return info.raw;
}
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 u32 EntityGroupFilter::makeCollisionFilterInfo(ContactLayer layer, GroundHit ground_hit) {
return EntityCollisionFilterInfo::make(layer, ground_hit).raw;
}
inline ContactLayer EntityGroupFilter::getCollisionFilterInfoLayer(u32 info) {
return EntityCollisionFilterInfo(info).getLayer();
}
inline u32 EntityGroupFilter::makeQueryCollisionMask(u32 layer_mask, GroundHit ground_hit,
bool unk) {
RayCastCollisionMask mask;
mask.layer_mask = layer_mask;
mask.ground_hit_type = ground_hit.value();
mask.unk.SetBit(unk);
return mask.raw;
}
inline GroundHit EntityGroupFilter::getQueryCollisionMaskGroundHit(u32 info) {
return RayCastCollisionMask(info).ground_hit_type.Value();
}
inline void EntityGroupFilter::getCollisionFilterInfoLayerAndGroundHit(u32 info,
ContactLayer* layer,
GroundHit* ground_hit) {
EntityCollisionFilterInfo info_{info};
*layer = info_.getLayer();
*ground_hit = info_.getGroundHit();
}
inline const char* EntityGroupFilter::getCollisionFilterInfoLayerText(u32 info) {
EntityCollisionFilterInfo info_{info};
if (info_.is_ground_hit_mask) {
return "GroundHitMaskMode";
}
return contactLayerToText(getCollisionFilterInfoLayer(info));
}
inline void EntityGroupFilter::setLayerCustomMask(ContactLayer layer, u32 mask) {
mMasks[layer] = mask;
}
inline u32 EntityGroupFilter::getCollisionFilterInfoGroupHandlerIdx(u32 info) {
return EntityCollisionFilterInfo(info).group_handler_index;
}
inline u32 EntityGroupFilter::makeCollisionFilterInfo(ContactLayer layer, GroundHit ground_hit,
u32 unk5, u32 unk10) {
EntityCollisionFilterInfo info;
info.data.layer.Init(layer);
info.data.unk5.Init(unk5);
info.data.unk10.Init(unk10);
info.data.ground_hit.Init(ground_hit);
info.unk30 = true;
return info.raw;
}
inline void EntityGroupFilter::setEntityLayerCollisionEnabledMask(ContactLayer layer, u32 mask) {
m_collisionLookupTable[layer] = mask;
}
} // namespace ksys::phys

View File

@ -50,7 +50,7 @@ void GroupFilter::removeSystemGroupHandler(SystemGroupHandler* handler) {
mUsedList.erase(handler);
}
u32 SystemGroupHandler::m7() {
u32 SystemGroupHandler::makeRagdollCollisionFilterInfo(GroundHit ground_hit) {
return 0;
}

View File

@ -18,8 +18,8 @@ public:
virtual ~SystemGroupHandler() = default;
virtual u32 makeCollisionFilterInfo(u32 info, ContactLayer layer, GroundHit ground_hit) = 0;
virtual u32 m6() = 0;
virtual u32 m7();
virtual u32 makeQueryCollisionMask(u32 layer_mask, GroundHit ground_hit, bool unk) = 0;
virtual u32 makeRagdollCollisionFilterInfo(GroundHit ground_hit);
virtual bool m8() = 0;
int getIndex() const { return mIndex; }
@ -75,15 +75,31 @@ public:
m_collisionLookupTable[layer - getLayerFirst()] = mask;
}
virtual bool m2() { return true; }
virtual void m3() = 0;
virtual void m4() = 0;
virtual void m5() = 0;
virtual void m6() = 0;
virtual void m7() = 0;
virtual void m8() = 0;
virtual bool m2(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;
/// Get the layer from a collision filter mask.
virtual ContactLayer getCollisionFilterInfoLayer(u32 info) = 0;
/// Make a query collision mask with the specified layer mask, ground hit type and flag.
virtual u32 makeQueryCollisionMask(u32 layer_mask, GroundHit ground_hit, bool unk) = 0;
/// Get the ground hit type from a query collision mask.
virtual GroundHit getQueryCollisionMaskGroundHit(u32 info) = 0;
/// Get the layer and ground hit type from a collision filter mask.
virtual void getCollisionFilterInfoLayerAndGroundHit(u32 info, ContactLayer* layer,
GroundHit* ground_hit) = 0;
/// Get the layer from a collision filter mask.
virtual const char* getCollisionFilterInfoLayerText(u32 info) = 0;
virtual void setLayerCustomMask(ContactLayer layer, u32 mask) {}
virtual void m10() = 0;
/// Get the group handler index from a collision filter mask.
virtual u32 getCollisionFilterInfoGroupHandlerIdx(u32 info) = 0;
protected:
virtual void doInitSystemGroupHandlerLists_(sead::Heap* heap) = 0;

View File

@ -80,6 +80,11 @@ constexpr auto LastEntity = ContactLayer::EntityMeshVisualizer;
constexpr auto FirstSensor = ContactLayer::SensorObject;
constexpr auto LastSensor = ContactLayer::SensorCustomReceiver;
constexpr bool isEntityGroundLayer(ContactLayer::ValueType layer) {
return layer == ContactLayer::EntityGround || layer == ContactLayer::EntityGroundSmooth ||
layer == ContactLayer::EntityGroundRough;
}
SEAD_ENUM(Material,
Undefined,\
Soil,\
@ -180,6 +185,22 @@ enum class MotionType {
Invalid = -1,
};
enum class GroundCollisionMode {
/// Ground collision is not handled in any special way.
Normal = 0,
/// Any collision with a non-ground layer is ignored.
IgnoreNonGround = 1,
/// Any collision with a ground layer is ignored.
IgnoreGround = 2,
};
enum class WaterCollisionMode {
/// Water collision is not handled in any special way.
Normal = 0,
/// Any collision with a water layer is ignored.
IgnoreWater = 1,
};
union ReceiverMask {
union Data {
util::BitField<0, 5, u32> layer;
@ -229,6 +250,12 @@ union EntityCollisionFilterInfo {
u32 raw;
util::BitField<0, 5, u32> layer;
// TODO: figure out what this is
util::BitField<5, 5, u32> unk5;
util::BitField<10, 5, u32> unk10;
/// Layers to collide with for EntityQueryCustomReceiver entities.
// XXX: was 17 chosen because ContactLayer::EntityQueryCustomReceiver = 17?
util::BitField<5, 17, u32> query_custom_receiver_layer_mask;
util::BitField<24, 1, u32> unk24;
util::BitField<25, 1, u32> unk25;
util::BitField<26, 4, u32> ground_hit;
@ -244,7 +271,7 @@ union EntityCollisionFilterInfo {
u32 raw;
util::BitField<0, 1, u32> unk;
util::BitField<8, 16, u32> ground_hit_types;
util::BitField<24, 1, u32> unk24;
util::BitField<23, 1, u32> unk23;
util::BitField<25, 5, u32> layer;
};
@ -281,17 +308,35 @@ union EntityCollisionFilterInfo {
u32 raw;
Data data;
GroundHitMask ground_hit;
util::BitField<5, 1, bool, u32> unk5;
/// Whether ground collision is disabled.
util::BitField<6, 1, bool, u32> no_ground_collision;
/// Whether water collision is disabled.
util::BitField<7, 1, bool, u32> no_water_collision;
util::BitField<5, 2, GroundCollisionMode, u32> ground_col_mode;
util::BitField<7, 1, WaterCollisionMode, u32> water_col_mode;
util::BitField<16, 10, u32> group_handler_index;
/// If this flag is set, then this entity will always collide with ground or water,
/// regardless of the configured GroundCollisionMode or WaterCollisionMode modes.
// TODO: is this "is_ragdoll"? See EntitySystemGroupHandler::makeCollisionFilterInfo.
util::BitField<30, 1, bool, u32> unk30;
util::BitField<31, 1, bool, u32> is_ground_hit_mask;
};
static_assert(sizeof(EntityCollisionFilterInfo) == sizeof(u32));
/// Collision mask that is used for raycast-based queries.
union RayCastCollisionMask {
constexpr explicit RayCastCollisionMask(u32 raw_ = 0) : raw(raw_) {}
constexpr RayCastCollisionMask(const RayCastCollisionMask&) = default;
constexpr RayCastCollisionMask& operator=(const RayCastCollisionMask& m) {
raw = m.raw;
return *this;
}
constexpr bool operator==(RayCastCollisionMask rhs) const { return raw == rhs.raw; }
constexpr bool operator!=(RayCastCollisionMask rhs) const { return raw != rhs.raw; }
util::BitField<0, 17, u32> layer_mask;
util::BitField<17, 1, u32> unk;
util::BitField<18, 10, u32> group_handler_index;
util::BitField<28, 4, GroundHit::ValueType, u32> ground_hit_type;
u32 raw;
};
ContactLayerType getContactLayerType(ContactLayer layer);
u32 makeContactLayerMask(ContactLayer layer);
u32 getContactLayerBase(ContactLayerType type);

View File

@ -132,8 +132,7 @@ struct BitField {
template <auto bits_ = bits, typename = std::enable_if_t<bits_ == 1>>
inline constexpr void SetBit(bool set) {
const auto mask = set ? ((static_cast<StorageType>(1) << position) & GetMask()) : 0;
storage = (storage & ~GetMask()) | mask;
storage = (storage & ~GetMask()) | (set ? GetMask() : 0);
}
/// @warning This does *not* check whether the value fits within the mask,