ksys/phys: Clarify EntityCollisionMask structure and names

This commit is contained in:
Léo Lam 2022-12-18 18:36:02 +01:00
parent 30368facc0
commit 20be3a197a
No known key found for this signature in database
GPG Key ID: 0DF30F9081000741
6 changed files with 77 additions and 65 deletions

View File

@ -610,7 +610,7 @@ bool RigidBody::isGroundCollisionEnabled() const {
bool enabled = false;
enabled |= info.ground_col_mode != GroundCollisionMode::IgnoreGround;
enabled |= info.unk30;
enabled |= info.is_ragdoll;
return enabled;
}
@ -636,7 +636,7 @@ bool RigidBody::isWaterCollisionEnabled() const {
bool enabled = false;
// unk30 enables all collisions?
enabled |= info.unk30;
enabled |= info.is_ragdoll;
enabled |= info.water_col_mode != WaterCollisionMode::IgnoreWater;
return enabled;
}

View File

@ -344,7 +344,7 @@ RigidBodyT* RigidBodyFromShape::make(const Shape& shape, RigidBodyInstanceParam*
const u32 idx = group_handler ? group_handler->getIndex() : 0;
collision_filter_info = [&] {
EntityCollisionMask info{collision_filter_info};
info.group_handler_index.SetUnsafe(idx);
info.regular.group_handler_index.SetUnsafe(idx);
return info.raw;
}();
} else {

View File

@ -28,9 +28,9 @@ bool ClosestPointQuery::isSuccess() const {
void ClosestPointQuery::setLayerMasksAndBodyCollisionFilterInfo(const LayerMaskBuilder& builder) {
EntityCollisionMask mask;
mask.data.query_custom_receiver_layer_mask =
mask.regular.query_custom_receiver_layer_mask =
builder.getMasks()[int(ContactLayerType::Entity)].layers;
mask.data.layer = ContactLayer::EntityQueryCustomReceiver;
mask.regular.layer = ContactLayer::EntityQueryCustomReceiver;
mBody->setCollisionFilterInfo(mask.raw);
setLayerMasks(builder);

View File

@ -112,27 +112,30 @@ hkBool EntityGroupFilter::testCollisionForEntities(u32 infoA, u32 infoB) const {
const EntityCollisionMask a{infoA};
const EntityCollisionMask b{infoB};
constexpr auto GroupHandlerIdxMask = decltype(a.group_handler_index)::GetMask();
constexpr auto GroupHandlerIdxShift = decltype(a.group_handler_index)::StartBit();
if (!EntityCollisionMask(infoA | infoB).is_ground_hit_mask) {
if (a.unk30 && b.unk30) {
constexpr auto GroupHandlerIdxMask = decltype(a.regular.group_handler_index)::GetMask();
constexpr auto GroupHandlerIdxShift = decltype(a.regular.group_handler_index)::StartBit();
if (a.is_ragdoll && b.is_ragdoll) {
if (((infoA ^ infoB) & GroupHandlerIdxMask) != 0) {
if (testHandler(a.group_handler_index) || testHandler(b.group_handler_index))
if (testHandler(a.regular.group_handler_index) ||
testHandler(b.regular.group_handler_index)) {
return false;
}
} else if ((infoA & GroupHandlerIdxMask) >> GroupHandlerIdxShift != 0) {
if (a.data.unk5 == b.data.unk10 || b.data.unk5 == a.data.unk10)
if (a.regular.ragdoll_bone_index == b.regular.ragdoll_bone_index2 ||
b.regular.ragdoll_bone_index == a.regular.ragdoll_bone_index2)
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());
const auto layerA = static_cast<ContactLayer::ValueType>(a.regular.layer.Value());
const auto layerB = static_cast<ContactLayer::ValueType>(b.regular.layer.Value());
if (layerA != ContactLayer::EntityQueryCustomReceiver &&
layerB != ContactLayer::EntityQueryCustomReceiver) {
if (!a.unk30 && !b.unk30) {
if (!a.is_ragdoll && !b.is_ragdoll) {
if (!shouldHandleGroundCollision(infoA, infoB, layerA, layerB))
return false;
if (!shouldHandleWaterCollision(infoA, infoB, layerA, layerB))
@ -140,8 +143,10 @@ hkBool EntityGroupFilter::testCollisionForEntities(u32 infoA, u32 infoB) const {
}
if (((infoA ^ infoB) & GroupHandlerIdxMask) != 0) {
if (testHandler(a.group_handler_index) || testHandler(b.group_handler_index))
if (testHandler(a.regular.group_handler_index) ||
testHandler(b.regular.group_handler_index)) {
return false;
}
} else if (((infoA & GroupHandlerIdxMask) >> GroupHandlerIdxShift) > 15) {
return false;
}
@ -154,9 +159,9 @@ hkBool EntityGroupFilter::testCollisionForEntities(u32 infoA, u32 infoB) const {
}
if (layerA == ContactLayer::EntityQueryCustomReceiver)
return a.data.query_custom_receiver_layer_mask & (1 << layerB);
return a.regular.query_custom_receiver_layer_mask & (1 << layerB);
else
return b.data.query_custom_receiver_layer_mask & (1 << layerA);
return b.regular.query_custom_receiver_layer_mask & (1 << layerA);
}
if (a.is_ground_hit_mask && b.is_ground_hit_mask) {
@ -176,37 +181,37 @@ hkBool EntityGroupFilter::testCollisionForEntities(u32 infoA, u32 infoB) const {
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());
const auto layerB = static_cast<ContactLayer::ValueType>(b.regular.layer.Value());
entity_mask = b;
ground_hit_mask = a;
if (layerB == ContactLayer::EntityQueryCustomReceiver)
return b.data.query_custom_receiver_layer_mask & (1 << layerA);
return b.regular.query_custom_receiver_layer_mask & (1 << layerA);
if (!b.unk30 && !shouldHandleGroundCollision(infoA, infoB, layerA, layerB))
if (!b.is_ragdoll && !shouldHandleGroundCollision(infoA, infoB, layerA, layerB))
return false;
if (!b.unk30 && !shouldHandleWaterCollision(infoA, infoB, layerA, layerB))
if (!b.is_ragdoll && !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 layerA = static_cast<ContactLayer::ValueType>(a.regular.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);
return a.regular.query_custom_receiver_layer_mask & (1 << layerB);
if (!a.unk30 && !shouldHandleGroundCollision(infoA, infoB, layerA, layerB))
if (!a.is_ragdoll && !shouldHandleGroundCollision(infoA, infoB, layerA, layerB))
return false;
if (!a.unk30 && !shouldHandleWaterCollision(infoA, infoB, layerA, layerB))
if (!a.is_ragdoll && !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));
return !(ground_hit_mask.ground_hit.ground_hit_types & (1 << entity_mask.regular.ground_hit));
}
hkBool EntityGroupFilter::testCollisionForPhantom(u32 infoPhantom, u32 infoB) const {
@ -217,7 +222,7 @@ hkBool EntityGroupFilter::testCollisionForPhantom(u32 infoPhantom, u32 infoB) co
const EntityCollisionMask info{infoB};
if (info.is_ground_hit_mask)
return infoPhantomData.raw & (1 << info.ground_hit.getLayer());
return infoPhantomData.layer_mask & (1 << info.data.layer);
return infoPhantomData.layer_mask & (1 << info.regular.layer);
}
hkBool EntityGroupFilter::isCollisionEnabled(const hkpCollidable& a, const hkpCollidable& b) const {
@ -336,19 +341,19 @@ hkBool EntityGroupFilter::testCollisionForRayCasting(u32 infoRayCast, u32 info)
if (b.is_ground_hit_mask)
return checkCollisionWithGroundHitMask(b.ground_hit, a);
const u32 bHandlerIdx = b.group_handler_index;
const u32 bHandlerIdx = b.regular.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);
return a.layer_mask & (1 << b.regular.layer);
}
if (testHandler(aHandlerIdx) || testHandler(bHandlerIdx))
return false;
return a.layer_mask & (1 << b.data.layer);
return a.layer_mask & (1 << b.regular.layer);
}
KSYS_ALWAYS_INLINE hkBool EntityGroupFilter::isCollisionEnabled(const hkpShapeRayCastInput& aInput,
@ -420,7 +425,7 @@ u32 makeEntityCollisionMask(ContactLayer layer, u32 mask) {
if (current.is_ground_hit_mask) {
return makeEntityGroundHitMaskImpl<true>(layer, mask).raw;
} else {
current.data.layer.SetUnsafe(layer);
current.regular.layer.SetUnsafe(layer);
return current.raw;
}
}
@ -430,7 +435,7 @@ u32 setEntityCollisionMaskGroundHit(GroundHit ground_hit, u32 mask) {
if (current.is_ground_hit_mask) {
// This shouldn't happen: this function is not supposed to be called on ground hit masks.
} else {
current.data.ground_hit.SetUnsafe(ground_hit);
current.regular.ground_hit.SetUnsafe(ground_hit);
}
return current.raw;
}

View File

@ -109,17 +109,17 @@ inline u32 EntitySystemGroupHandler::makeCollisionFilterInfo(u32 info, ContactLa
EntityCollisionMask 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;
result.regular.layer.Init(layer);
result.regular.ragdoll_bone_index.Init(current_info.regular.ragdoll_bone_index);
result.regular.ragdoll_bone_index2.Init(current_info.regular.ragdoll_bone_index2);
result.regular.group_handler_index.Init(getIndex());
result.regular.ground_hit.Init(ground_hit);
result.is_ragdoll = true;
} else {
result.data.layer.Init(layer);
result.regular.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);
result.regular.group_handler_index.Init(getIndex());
result.regular.ground_hit.Init(ground_hit);
}
return result.raw;
}
@ -136,9 +136,9 @@ inline u32 EntitySystemGroupHandler::makeQueryCollisionMask(u32 layer_mask, Grou
inline u32 EntitySystemGroupHandler::makeRagdollCollisionFilterInfo(GroundHit ground_hit) {
EntityCollisionMask info;
info.data.layer.Init(ContactLayer::EntityRagdoll);
info.group_handler_index.Init(getIndex());
info.data.ground_hit.Init(ground_hit);
info.regular.layer.Init(ContactLayer::EntityRagdoll);
info.regular.group_handler_index.Init(getIndex());
info.regular.ground_hit.Init(ground_hit);
return info.raw;
}
@ -193,17 +193,17 @@ inline void EntityGroupFilter::setLayerCustomMask(ContactLayer layer, u32 mask)
}
inline u32 EntityGroupFilter::getCollisionFilterInfoGroupHandlerIdx(u32 info) {
return EntityCollisionMask(info).group_handler_index;
return EntityCollisionMask(info).regular.group_handler_index;
}
inline u32 EntityGroupFilter::makeCollisionFilterInfo(ContactLayer layer, GroundHit ground_hit,
u32 unk5, u32 unk10) {
EntityCollisionMask 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;
info.regular.layer.Init(layer);
info.regular.ragdoll_bone_index.Init(unk5);
info.regular.ragdoll_bone_index2.Init(unk10);
info.regular.ground_hit.Init(ground_hit);
info.is_ragdoll = true;
return info.raw;
}

View File

@ -210,21 +210,28 @@ enum class WaterCollisionMode {
IgnoreWater = 1,
};
/// Collision filter info / collision mask that is used for entity rigid bodies.
/// https://docs.google.com/spreadsheets/d/e/2PACX-1vQyEL5_Wee3MI23c-nHa4dMPJDVen9TMMcrOUX7Wka9NAH1AW9bkkq7ZJHawJkSzGOqgHUYc-83t4Or/pubhtml
union EntityCollisionMask {
union Data {
union RegularMask {
ContactLayer getLayer() const { return int(layer); }
ContactLayer getLayerSensor() const { return int(layer + FirstSensor); }
GroundHit getGroundHit() const { return int(ground_hit); }
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;
/// Only valid for ragdoll masks.
util::BitField<5, 5, u32> ragdoll_bone_index;
/// Only valid for ragdoll masks.
util::BitField<10, 5, u32> ragdoll_bone_index2;
/// Only valid for CustomReceiver masks.
/// Layers to collide with for EntityQueryCustomReceiver entities.
util::BitField<5, NumRegularEntityLayers, u32> query_custom_receiver_layer_mask;
util::BitField<24, 1, u32> unk24;
util::BitField<25, 1, u32> unk25;
/// Only valid for non-CustomReceiver masks.
util::BitField<16, 10, u32> group_handler_index;
util::BitField<26, 4, u32> ground_hit;
};
@ -254,34 +261,34 @@ union EntityCollisionMask {
static EntityCollisionMask make(ContactLayer layer, GroundHit ground_hit) {
EntityCollisionMask mask;
mask.data.layer.Init(layer);
mask.data.ground_hit.Init(ground_hit);
mask.regular.layer.Init(layer);
mask.regular.ground_hit.Init(ground_hit);
return mask;
}
ContactLayer getLayer() const {
return is_ground_hit_mask ? ground_hit.getLayer() : data.getLayer();
return is_ground_hit_mask ? ground_hit.getLayer() : regular.getLayer();
}
ContactLayer getLayerSensor() const {
return is_ground_hit_mask ? ContactLayer(ContactLayer::SensorCustomReceiver) :
data.getLayerSensor();
regular.getLayerSensor();
}
GroundHit getGroundHit() const {
return is_ground_hit_mask ? GroundHit::HitAll : data.getGroundHit();
return is_ground_hit_mask ? GroundHit::HitAll : regular.getGroundHit();
}
u32 raw;
Data data;
RegularMask regular;
GroundHitMask ground_hit;
/// Only valid in non-ragdoll, non-CustomReceiver mode.
util::BitField<5, 2, GroundCollisionMode, u32> ground_col_mode;
/// Only valid in non-ragdoll, non-CustomReceiver 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<30, 1, bool, u32> is_ragdoll;
util::BitField<31, 1, bool, u32> is_ground_hit_mask;
};
static_assert(sizeof(EntityCollisionMask) == sizeof(u32));