mirror of
https://github.com/zeldaret/botw
synced 2026-08-02 00:14:36 -04:00
ksys/phys: Add more EntityGroupFilter functions
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -50,7 +50,7 @@ void GroupFilter::removeSystemGroupHandler(SystemGroupHandler* handler) {
|
||||
mUsedList.erase(handler);
|
||||
}
|
||||
|
||||
u32 SystemGroupHandler::m7() {
|
||||
u32 SystemGroupHandler::makeRagdollCollisionFilterInfo(GroundHit ground_hit) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user