mirror of
https://github.com/zeldaret/botw
synced 2026-05-23 06:54:18 -04:00
407 lines
11 KiB
C++
407 lines
11 KiB
C++
#pragma once
|
|
|
|
#include <basis/seadTypes.h>
|
|
#include <prim/seadEnum.h>
|
|
#include <prim/seadSafeString.h>
|
|
#include "KingSystem/Utils/BitField.h"
|
|
|
|
namespace ksys::phys {
|
|
|
|
enum class ContactLayerType {
|
|
Entity,
|
|
Sensor,
|
|
Invalid,
|
|
};
|
|
|
|
constexpr int NumContactLayerTypes = 2;
|
|
|
|
SEAD_ENUM(ContactLayer,
|
|
EntityObject,\
|
|
EntitySmallObject,\
|
|
EntityGroundObject,\
|
|
EntityPlayer,\
|
|
EntityNPC,\
|
|
EntityRagdoll,\
|
|
EntityWater,\
|
|
EntityAirWall,\
|
|
EntityGround,\
|
|
EntityGroundSmooth,\
|
|
EntityGroundRough,\
|
|
EntityRope,\
|
|
EntityTree,\
|
|
EntityNPC_NoHitPlayer,\
|
|
EntityHitOnlyWater,\
|
|
EntityWallForClimb,\
|
|
EntityHitOnlyGround,\
|
|
EntityQueryCustomReceiver,\
|
|
EntityForbidden18,\
|
|
EntityNoHit,\
|
|
EntityMeshVisualizer,\
|
|
EntityForbidden21,\
|
|
EntityForbidden22,\
|
|
EntityForbidden23,\
|
|
EntityForbidden24,\
|
|
EntityForbidden25,\
|
|
EntityForbidden26,\
|
|
EntityForbidden27,\
|
|
EntityForbidden28,\
|
|
EntityForbidden29,\
|
|
EntityForbidden30,\
|
|
EntityEnd,\
|
|
SensorObject,\
|
|
SensorSmallObject,\
|
|
SensorPlayer,\
|
|
SensorEnemy,\
|
|
SensorNPC,\
|
|
SensorHorse,\
|
|
SensorRope,\
|
|
SensorAttackPlayer,\
|
|
SensorAttackEnemy,\
|
|
SensorChemical,\
|
|
SensorTerror,\
|
|
SensorHitOnlyInDoor,\
|
|
SensorInDoor,\
|
|
SensorReserve13,\
|
|
SensorReserve14,\
|
|
SensorChemicalElement,\
|
|
SensorAttackCommon,\
|
|
SensorQueryOnly,\
|
|
SensorTree,\
|
|
SensorCamera,\
|
|
SensorMeshVisualizer,\
|
|
SensorNoHit,\
|
|
SensorReserve20,\
|
|
SensorCustomReceiver,\
|
|
SensorEnd)
|
|
|
|
constexpr int MaxNumLayersPerType = 32;
|
|
|
|
constexpr auto FirstEntity = ContactLayer::EntityObject;
|
|
constexpr auto LastEntity = ContactLayer::EntityMeshVisualizer;
|
|
|
|
constexpr auto FirstSensor = ContactLayer::SensorObject;
|
|
constexpr auto LastSensor = ContactLayer::SensorCustomReceiver;
|
|
|
|
// If the values of the two following constants are changed, most of the BitFields defined
|
|
// in this file will need to be updated.
|
|
constexpr int NumRegularEntityLayers = ContactLayer::EntityHitOnlyGround - FirstEntity + 1;
|
|
constexpr int NumRegularSensorLayers = ContactLayer::SensorMeshVisualizer - FirstSensor + 1;
|
|
static_assert(NumRegularEntityLayers == 17);
|
|
static_assert(NumRegularSensorLayers == 21);
|
|
|
|
constexpr bool isEntityGroundLayer(ContactLayer::ValueType layer) {
|
|
return layer == ContactLayer::EntityGround || layer == ContactLayer::EntityGroundSmooth ||
|
|
layer == ContactLayer::EntityGroundRough;
|
|
}
|
|
|
|
SEAD_ENUM(Material,
|
|
Undefined,\
|
|
Soil,\
|
|
Stone,\
|
|
Sand,\
|
|
Metal,\
|
|
WireNet,\
|
|
Grass,\
|
|
Wood,\
|
|
Water,\
|
|
Snow,\
|
|
Ice,\
|
|
Lava,\
|
|
Bog,\
|
|
HeavySand,\
|
|
Cloth,\
|
|
Glass,\
|
|
Bone,\
|
|
Rope,\
|
|
CharControl,\
|
|
Ragdoll,\
|
|
Surfing,\
|
|
GuardianFoot,\
|
|
HeavySnow,\
|
|
Unused0,\
|
|
LaunchPad,\
|
|
Conveyer,\
|
|
Rail,\
|
|
Grudge,\
|
|
Meat,\
|
|
Vegetable,\
|
|
Bomb,\
|
|
MagicBall,\
|
|
Barrier,\
|
|
AirWall,\
|
|
Misc,\
|
|
GrudgeSlow
|
|
)
|
|
|
|
constexpr bool isInvalidMaterial(Material::ValueType mat) {
|
|
return mat >= Material::size();
|
|
}
|
|
|
|
SEAD_ENUM(GroundHit,
|
|
Player,\
|
|
Animal,\
|
|
NPC,\
|
|
Camera,\
|
|
AttackHitPlayer,\
|
|
AttackHitEnemy,\
|
|
Arrow,\
|
|
Bomb,\
|
|
Magnet,\
|
|
CameraBody,\
|
|
IK,\
|
|
Grudge,\
|
|
MovingTrolley,\
|
|
LineOfSight,\
|
|
Giant,\
|
|
HitAll,\
|
|
Ignore
|
|
)
|
|
|
|
SEAD_ENUM(FloorCode,
|
|
None,\
|
|
Return,\
|
|
FlowStraight,\
|
|
FlowLeft,\
|
|
FlowRight,\
|
|
Slip,\
|
|
NarrowPlace,\
|
|
TopBroadleafTree,\
|
|
TopConiferousTree,\
|
|
Fall,\
|
|
Attach,\
|
|
NoImpulseUpperMove,\
|
|
NoPreventFall
|
|
)
|
|
|
|
SEAD_ENUM(WallCode,
|
|
None,\
|
|
NoClimb,\
|
|
Hang,\
|
|
LadderUp,\
|
|
Ladder,\
|
|
Slip,\
|
|
LadderSide,\
|
|
NoSlipRain,\
|
|
NoDashUpAndNoClimb,\
|
|
IceMakerBlock
|
|
)
|
|
|
|
enum class MotionType {
|
|
Dynamic = 0,
|
|
Fixed = 1,
|
|
Keyframed = 2,
|
|
Unknown = 3,
|
|
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,
|
|
};
|
|
|
|
/// 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 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;
|
|
|
|
/// Only valid for ragdoll masks.
|
|
util::BitField<5, 5, u32> ragdoll_bone_index;
|
|
/// Only valid for ragdoll masks.
|
|
util::BitField<10, 5, u32> ragdoll_parent_bone_index;
|
|
|
|
/// Only valid for CustomReceiver masks.
|
|
/// Layers to collide with for EntityQueryCustomReceiver entities.
|
|
util::BitField<5, NumRegularEntityLayers, u32> query_custom_receiver_layer_mask;
|
|
|
|
/// Only valid for non-CustomReceiver masks.
|
|
util::BitField<16, 10, u32> group_handler_index;
|
|
util::BitField<26, 4, u32> ground_hit;
|
|
};
|
|
|
|
union GroundHitMask {
|
|
ContactLayer getLayer() const { return int(layer); }
|
|
|
|
void addGroundHit(GroundHit hit) {
|
|
raw |= (1 << hit) << decltype(ground_hit_types)::StartBit();
|
|
}
|
|
|
|
u32 raw;
|
|
util::BitField<0, 1, u32> unk;
|
|
util::BitField<8, 16, u32> ground_hit_types;
|
|
util::BitField<23, 1, u32> unk23;
|
|
util::BitField<25, 5, u32> layer;
|
|
};
|
|
|
|
constexpr explicit EntityCollisionMask(u32 raw_ = 0) : raw(raw_) {}
|
|
constexpr EntityCollisionMask(const EntityCollisionMask&) = default;
|
|
constexpr EntityCollisionMask& operator=(const EntityCollisionMask& m) {
|
|
raw = m.raw;
|
|
return *this;
|
|
}
|
|
|
|
bool operator==(EntityCollisionMask rhs) const { return raw == rhs.raw; }
|
|
bool operator!=(EntityCollisionMask rhs) const { return raw != rhs.raw; }
|
|
|
|
static EntityCollisionMask make(ContactLayer layer, GroundHit ground_hit) {
|
|
EntityCollisionMask mask;
|
|
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() : regular.getLayer();
|
|
}
|
|
|
|
ContactLayer getLayerSensor() const {
|
|
return is_ground_hit_mask ? ContactLayer(ContactLayer::SensorCustomReceiver) :
|
|
regular.getLayerSensor();
|
|
}
|
|
|
|
GroundHit getGroundHit() const {
|
|
return is_ground_hit_mask ? GroundHit::HitAll : regular.getGroundHit();
|
|
}
|
|
|
|
u32 raw;
|
|
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;
|
|
/// If this flag is set, then this entity will always collide with ground or water,
|
|
/// regardless of the configured GroundCollisionMode or WaterCollisionMode modes.
|
|
util::BitField<30, 1, bool, u32> is_ragdoll;
|
|
util::BitField<31, 1, bool, u32> is_ground_hit_mask;
|
|
};
|
|
static_assert(sizeof(EntityCollisionMask) == sizeof(u32));
|
|
|
|
/// Collision mask that is used for raycast-based queries against entities.
|
|
union EntityQueryCollisionMask {
|
|
constexpr explicit EntityQueryCollisionMask(u32 raw_ = 0) : raw(raw_) {}
|
|
constexpr EntityQueryCollisionMask(const EntityQueryCollisionMask&) = default;
|
|
constexpr EntityQueryCollisionMask& operator=(const EntityQueryCollisionMask& m) {
|
|
raw = m.raw;
|
|
return *this;
|
|
}
|
|
constexpr bool operator==(EntityQueryCollisionMask rhs) const { return raw == rhs.raw; }
|
|
constexpr bool operator!=(EntityQueryCollisionMask rhs) const { return raw != rhs.raw; }
|
|
|
|
util::BitField<0, NumRegularEntityLayers, 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;
|
|
};
|
|
|
|
union SensorCollisionMask {
|
|
struct CustomReceiverTag {};
|
|
|
|
union Data {
|
|
ContactLayer getLayer() const { return int(layer) + FirstSensor; }
|
|
|
|
/// The sensor's contact layer.
|
|
/// @note Add FirstSensor to get the actual ContactLayer value.
|
|
util::BitField<0, 5, u32> layer;
|
|
/// Whether `ignored_layer` contains a valid layer.
|
|
util::BitField<5, 1, bool, u32> has_ignored_layer;
|
|
/// Contact layer to ignore during collision detection. Only valid if `has_ignored_layer`.
|
|
/// @note Add FirstSensor to get the actual ContactLayer value.
|
|
util::BitField<6, 5, u32> ignored_layer;
|
|
};
|
|
|
|
union CustomReceiverData {
|
|
util::BitField<0, NumRegularSensorLayers, u32> layer;
|
|
util::BitField<0, NumRegularSensorLayers, u32> layer_mask;
|
|
};
|
|
|
|
constexpr SensorCollisionMask() : raw(0) {}
|
|
constexpr explicit SensorCollisionMask(CustomReceiverTag) : raw(0) {
|
|
is_custom_receiver = true;
|
|
}
|
|
constexpr explicit SensorCollisionMask(u32 raw_) : raw(raw_) {}
|
|
constexpr SensorCollisionMask(const SensorCollisionMask&) = default;
|
|
constexpr SensorCollisionMask& operator=(const SensorCollisionMask& m) {
|
|
raw = m.raw;
|
|
return *this;
|
|
}
|
|
|
|
static SensorCollisionMask make(ContactLayer layer) {
|
|
SensorCollisionMask mask;
|
|
if (layer == ContactLayer::SensorCustomReceiver) {
|
|
mask.is_custom_receiver = true;
|
|
mask.custom_receiver_data.layer.Init(ContactLayer::SensorCustomReceiver - FirstSensor);
|
|
} else {
|
|
mask.is_custom_receiver = false;
|
|
mask.data.layer.Init(layer - FirstSensor);
|
|
}
|
|
return mask;
|
|
}
|
|
|
|
ContactLayer getLayer() const {
|
|
return is_custom_receiver ? ContactLayer::SensorCustomReceiver : data.getLayer();
|
|
}
|
|
|
|
u32 raw;
|
|
Data data;
|
|
CustomReceiverData custom_receiver_data;
|
|
util::BitField<21, 10, u32> group_handler_index;
|
|
util::BitField<31, 1, bool, u32> is_custom_receiver;
|
|
};
|
|
|
|
/// Collision mask that is used for raycast-based queries against sensors.
|
|
union SensorQueryCollisionMask {
|
|
constexpr explicit SensorQueryCollisionMask(u32 raw_ = 0) : raw(raw_) {}
|
|
constexpr SensorQueryCollisionMask(const SensorQueryCollisionMask&) = default;
|
|
constexpr SensorQueryCollisionMask& operator=(const SensorQueryCollisionMask& m) {
|
|
raw = m.raw;
|
|
return *this;
|
|
}
|
|
constexpr bool operator==(SensorQueryCollisionMask rhs) const { return raw == rhs.raw; }
|
|
constexpr bool operator!=(SensorQueryCollisionMask rhs) const { return raw != rhs.raw; }
|
|
|
|
util::BitField<0, NumRegularSensorLayers, u32> layer_mask;
|
|
util::BitField<22, 10, u32> group_handler_index;
|
|
u32 raw;
|
|
};
|
|
|
|
ContactLayerType getContactLayerType(ContactLayer layer);
|
|
u32 makeContactLayerMask(ContactLayer layer);
|
|
u32 getContactLayerBase(ContactLayerType type);
|
|
int getContactLayerBaseRelativeValue(ContactLayer layer);
|
|
const char* contactLayerToText(ContactLayer layer);
|
|
ContactLayer contactLayerFromText(const sead::SafeString& text);
|
|
|
|
const char* materialToText(Material material);
|
|
Material materialFromText(const sead::SafeString& text);
|
|
|
|
const char* groundHitToText(GroundHit hit);
|
|
GroundHit groundHitFromText(const sead::SafeString& text);
|
|
|
|
const char* floorCodeToText(FloorCode code);
|
|
FloorCode floorCodeFromText(const sead::SafeString& text);
|
|
|
|
const char* wallCodeToText(WallCode code);
|
|
WallCode wallCodeFromText(const sead::SafeString& text);
|
|
|
|
MotionType motionTypeFromText(const sead::SafeString& text);
|
|
|
|
} // namespace ksys::phys
|