From 71a361f54e1ccd313a7153b9a1806ce74ddfad2f Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Sat, 17 Jun 2017 15:58:13 -1000 Subject: [PATCH] Work on collision related implementations --- Runtime/Collision/CAABoxFilter.cpp | 16 + Runtime/Collision/CAABoxFilter.hpp | 19 + Runtime/Collision/CBallFilter.cpp | 11 + Runtime/Collision/CBallFilter.hpp | 19 + Runtime/Collision/CCollidableAABox.cpp | 21 +- Runtime/Collision/CCollidableAABox.hpp | 1 + Runtime/Collision/CCollidableSphere.cpp | 5 + Runtime/Collision/CCollidableSphere.hpp | 1 + Runtime/Collision/CCollisionInfo.cpp | 23 +- Runtime/Collision/CCollisionInfo.hpp | 50 +- Runtime/Collision/CCollisionInfoList.hpp | 24 +- Runtime/Collision/CCollisionPrimitive.cpp | 253 ++++++++- Runtime/Collision/CCollisionPrimitive.hpp | 90 ++- Runtime/Collision/CGameCollision.cpp | 630 ++++++++++++++++++++- Runtime/Collision/CGameCollision.hpp | 62 +- Runtime/Collision/CMakeLists.txt | 5 +- Runtime/Collision/CMetroidAreaCollider.cpp | 121 ++++ Runtime/Collision/CMetroidAreaCollider.hpp | 67 ++- Runtime/Collision/CollisionUtil.cpp | 55 ++ Runtime/Collision/CollisionUtil.hpp | 10 +- Runtime/Collision/ICollisionFilter.hpp | 21 + Runtime/Weapon/CGrappleArm.hpp | 3 +- Runtime/Weapon/CPlayerGun.hpp | 2 + Runtime/World/CActor.cpp | 8 + Runtime/World/CActor.hpp | 1 + Runtime/World/CPhysicsActor.cpp | 18 +- Runtime/World/CPhysicsActor.hpp | 44 +- Runtime/World/CPlayer.cpp | 44 +- Runtime/World/CPlayer.hpp | 20 +- Runtime/World/CScriptPlatform.cpp | 8 + Runtime/World/CScriptPlatform.hpp | 1 + Runtime/World/ScriptObjectSupport.hpp | 2 +- 32 files changed, 1521 insertions(+), 134 deletions(-) create mode 100644 Runtime/Collision/CAABoxFilter.cpp create mode 100644 Runtime/Collision/CAABoxFilter.hpp create mode 100644 Runtime/Collision/CBallFilter.cpp create mode 100644 Runtime/Collision/CBallFilter.hpp create mode 100644 Runtime/Collision/ICollisionFilter.hpp diff --git a/Runtime/Collision/CAABoxFilter.cpp b/Runtime/Collision/CAABoxFilter.cpp new file mode 100644 index 000000000..ae0700229 --- /dev/null +++ b/Runtime/Collision/CAABoxFilter.cpp @@ -0,0 +1,16 @@ +#include "CAABoxFilter.hpp" + +namespace urde +{ + +void CAABoxFilter::Filter(const CCollisionInfoList& in, CCollisionInfoList& out) const +{ + FilterBoxFloorCollisions(in, out); +} + +void CAABoxFilter::FilterBoxFloorCollisions(const CCollisionInfoList& in, CCollisionInfoList& out) +{ + /* TODO: finish */ +} + +} diff --git a/Runtime/Collision/CAABoxFilter.hpp b/Runtime/Collision/CAABoxFilter.hpp new file mode 100644 index 000000000..cb9e693aa --- /dev/null +++ b/Runtime/Collision/CAABoxFilter.hpp @@ -0,0 +1,19 @@ +#ifndef __URDE_CAABOXFILTER_HPP__ +#define __URDE_CAABOXFILTER_HPP__ + +#include "ICollisionFilter.hpp" + +namespace urde +{ + +class CAABoxFilter : public ICollisionFilter +{ +public: + CAABoxFilter(CActor& actor) : ICollisionFilter(actor) {} + void Filter(const CCollisionInfoList& in, CCollisionInfoList& out) const; + static void FilterBoxFloorCollisions(const CCollisionInfoList& in, CCollisionInfoList& out); +}; + +} + +#endif // __URDE_CAABOXFILTER_HPP__ diff --git a/Runtime/Collision/CBallFilter.cpp b/Runtime/Collision/CBallFilter.cpp new file mode 100644 index 000000000..2d8ee1e64 --- /dev/null +++ b/Runtime/Collision/CBallFilter.cpp @@ -0,0 +1,11 @@ +#include "CBallFilter.hpp" + +namespace urde +{ + +void CBallFilter::Filter(const CCollisionInfoList& in, CCollisionInfoList& out) const +{ + +} + +} diff --git a/Runtime/Collision/CBallFilter.hpp b/Runtime/Collision/CBallFilter.hpp new file mode 100644 index 000000000..131264c33 --- /dev/null +++ b/Runtime/Collision/CBallFilter.hpp @@ -0,0 +1,19 @@ +#ifndef __URDE_CBALLFILTER_HPP__ +#define __URDE_CBALLFILTER_HPP__ + +#include "ICollisionFilter.hpp" + +namespace urde +{ +class CPhysicsActor; + +class CBallFilter : public ICollisionFilter +{ +public: + CBallFilter(CActor& actor) : ICollisionFilter(actor) {} + void Filter(const CCollisionInfoList& in, CCollisionInfoList& out) const; +}; + +} + +#endif // __URDE_CBALLFILTER_HPP__ diff --git a/Runtime/Collision/CCollidableAABox.cpp b/Runtime/Collision/CCollidableAABox.cpp index dc08e5b18..230af7c4b 100644 --- a/Runtime/Collision/CCollidableAABox.cpp +++ b/Runtime/Collision/CCollidableAABox.cpp @@ -1,4 +1,5 @@ #include "CCollidableAABox.hpp" +#include "CollisionUtil.hpp" namespace urde { @@ -68,14 +69,26 @@ bool CCollidableAABox::CollideMovingSphere(const CInternalCollisionStructure &, namespace Collide { -bool AABox_AABox(const CInternalCollisionStructure &, CCollisionInfoList &) +bool AABox_AABox(const CInternalCollisionStructure& collision, CCollisionInfoList& list) { - return false; + const CCollidableAABox& box0 = static_cast(collision.GetLeft().GetPrim()); + const CCollidableAABox& box1 = static_cast(collision.GetRight().GetPrim()); + + zeus::CAABox aabb0 = box0.Transform(collision.GetLeft().GetTransform()); + zeus::CAABox aabb1 = box1.Transform(collision.GetRight().GetTransform()); + + return CollisionUtil::AABoxAABoxIntersection(aabb0, box0.GetMaterial(), aabb1, box1.GetMaterial(), list); } -bool AABox_AABox_Bool(const CInternalCollisionStructure &) +bool AABox_AABox_Bool(const CInternalCollisionStructure& collision) { - return false; + const CCollidableAABox& box0 = static_cast(collision.GetLeft().GetPrim()); + const CCollidableAABox& box1 = static_cast(collision.GetRight().GetPrim()); + + zeus::CAABox aabb0 = box0.Transform(collision.GetLeft().GetTransform()); + zeus::CAABox aabb1 = box1.Transform(collision.GetRight().GetTransform()); + + return CollisionUtil::AABoxAABoxIntersection(aabb0, aabb1); } } diff --git a/Runtime/Collision/CCollidableAABox.hpp b/Runtime/Collision/CCollidableAABox.hpp index 4738553be..3e51daf1c 100644 --- a/Runtime/Collision/CCollidableAABox.hpp +++ b/Runtime/Collision/CCollidableAABox.hpp @@ -28,6 +28,7 @@ public: virtual zeus::CAABox CalculateLocalAABox() const; virtual FourCC GetPrimType() const; virtual CRayCastResult CastRayInternal(const CInternalRayCastStructure&) const; + const zeus::CAABox& GetAABB() const { return x10_aabox; } static const CCollisionPrimitive::Type& GetType(); static void SetStaticTableIndex(u32 index); diff --git a/Runtime/Collision/CCollidableSphere.cpp b/Runtime/Collision/CCollidableSphere.cpp index dce62abd7..34af61cc1 100644 --- a/Runtime/Collision/CCollidableSphere.cpp +++ b/Runtime/Collision/CCollidableSphere.cpp @@ -32,6 +32,11 @@ void CCollidableSphere::SetSphereCenter(const zeus::CVector3f&) } +zeus::CSphere CCollidableSphere::Transform(const zeus::CTransform& xf) const +{ + return zeus::CSphere(xf * x10_sphere.position, x10_sphere.radius); +} + u32 CCollidableSphere::GetTableIndex() const { return sTableIndex; } zeus::CAABox CCollidableSphere::CalculateAABox(const zeus::CTransform&) const { return {}; } diff --git a/Runtime/Collision/CCollidableSphere.hpp b/Runtime/Collision/CCollidableSphere.hpp index 9d7cf8876..0efa558ec 100644 --- a/Runtime/Collision/CCollidableSphere.hpp +++ b/Runtime/Collision/CCollidableSphere.hpp @@ -25,6 +25,7 @@ public: const zeus::CSphere& GetSphere() const; void SetSphereCenter(const zeus::CVector3f&); + zeus::CSphere Transform(const zeus::CTransform& xf) const; virtual u32 GetTableIndex() const; virtual zeus::CAABox CalculateAABox(const zeus::CTransform&) const; diff --git a/Runtime/Collision/CCollisionInfo.cpp b/Runtime/Collision/CCollisionInfo.cpp index 0b8a8512a..c804aae42 100644 --- a/Runtime/Collision/CCollisionInfo.cpp +++ b/Runtime/Collision/CCollisionInfo.cpp @@ -3,9 +3,30 @@ namespace urde { +CCollisionInfo CCollisionInfo::GetSwapped() const +{ + CCollisionInfo ret; + ret.x0_point = x0_point; + ret.xc_ = xc_; + ret.x30_valid = x30_valid; + ret.x31_ = x31_; + ret.x38_materialLeft = x40_materialRight; + ret.x40_materialRight = x38_materialLeft; + ret.x48_normalLeft = x54_normalRight; + ret.x54_normalRight = x48_normalLeft; + return ret; +} + +void CCollisionInfo::Swap() +{ + x48_normalLeft = -x48_normalLeft; + x54_normalRight = -x54_normalRight; + std::swap(x38_materialLeft, x40_materialRight); +} + zeus::CVector3f CCollisionInfo::GetExtreme() const { - return (x18_ + (x0_aabox.min + x0_aabox.max) + x24_); + return x0_point + xc_ + x18_ + x24_; } } diff --git a/Runtime/Collision/CCollisionInfo.hpp b/Runtime/Collision/CCollisionInfo.hpp index 4574dc7d2..426014b0e 100644 --- a/Runtime/Collision/CCollisionInfo.hpp +++ b/Runtime/Collision/CCollisionInfo.hpp @@ -4,42 +4,54 @@ #include "RetroTypes.hpp" #include "CMaterialList.hpp" #include "zeus/CAABox.hpp" +#include "zeus/CMatrix3f.hpp" namespace urde { class CCollisionInfo { - zeus::CAABox x0_aabox = zeus::CAABox::skNullBox; + zeus::CVector3f x0_point; + zeus::CVector3f xc_; zeus::CVector3f x18_; zeus::CVector3f x24_; - bool x30_ = false; + bool x30_valid = false; bool x31_ = false; - /* u32 x34_; */ - CMaterialList x38_; - CMaterialList x40_; - zeus::CVector3f x48_; - zeus::CVector3f x54_; + CMaterialList x38_materialLeft; + CMaterialList x40_materialRight; + zeus::CVector3f x48_normalLeft; + zeus::CVector3f x54_normalRight; public: CCollisionInfo() = default; - CCollisionInfo(const zeus::CVector3f& v1, const CMaterialList& list1, const CMaterialList& list2, - const zeus::CVector3f& v2, const zeus::CVector3f& v3); - CCollisionInfo(const zeus::CVector3f& v1, const CMaterialList& list1, const CMaterialList& list2, - zeus::CVector3f const& v2); + CCollisionInfo(const zeus::CVector3f& point, const CMaterialList& list1, const CMaterialList& list2, + const zeus::CVector3f& normalLeft, const zeus::CVector3f& normalRight) + : x0_point(point), x30_valid(true), x31_(false), x38_materialLeft(list2), x40_materialRight(list1), + x48_normalLeft(normalLeft), x54_normalRight(normalRight) {} + CCollisionInfo(const zeus::CVector3f& point, const CMaterialList& list1, const CMaterialList& list2, + const zeus::CVector3f& normal) + : x0_point(point), x30_valid(true), x31_(false), x38_materialLeft(list2), x40_materialRight(list1), + x48_normalLeft(normal), x54_normalRight(-normal) {} CCollisionInfo(const zeus::CAABox& aabox, const CMaterialList& list1, const CMaterialList& list2, - const zeus::CVector3f& v1, const zeus::CVector3f& v2) - : x0_aabox(aabox) + const zeus::CVector3f& normalLeft, const zeus::CVector3f& normalRight) + : x0_point(aabox.min), + xc_(aabox.max.x - aabox.min.x, 0.f, 0.f), + x18_(0.f, aabox.max.y - aabox.min.y, 0.f), + x24_(0.f, 0.f, aabox.max.z - aabox.min.z), + x30_valid(true), x31_(true), x38_materialLeft(list2), + x40_materialRight(list1), x48_normalLeft(normalLeft), + x54_normalRight(normalRight) {} - bool IsValid() const; - void GetMaterialLeft() const; - void GetMaterialRight() const; + CCollisionInfo GetSwapped() const; + bool IsValid() const { return x30_valid; } + const CMaterialList& GetMaterialLeft() const { return x38_materialLeft; } + const CMaterialList& GetMaterialRight() const { return x40_materialRight; } zeus::CVector3f GetExtreme() const; void Swap(); void Transform(const zeus::CTransform&); - zeus::CVector3f GetNormalLeft() const; - zeus::CVector3f GetNormalRight() const; + zeus::CVector3f GetNormalLeft() const { return x48_normalLeft; } + zeus::CVector3f GetNormalRight() const { return x54_normalRight; } zeus::CVector3f GetOrigin() const; - zeus::CVector3f GetPoint() const; + zeus::CVector3f GetPoint() const { return x0_point; } }; } diff --git a/Runtime/Collision/CCollisionInfoList.hpp b/Runtime/Collision/CCollisionInfoList.hpp index e97c24220..3cf9c9954 100644 --- a/Runtime/Collision/CCollisionInfoList.hpp +++ b/Runtime/Collision/CCollisionInfoList.hpp @@ -2,10 +2,10 @@ #define __URDE_CCOLLISIONINFOLIST_HPP__ #include "RetroTypes.hpp" +#include "CCollisionInfo.hpp" namespace urde { -class CCollisionInfo; class CCollisionInfoList { rstl::reserved_vector x0_list; @@ -15,15 +15,23 @@ public: void GetAverageLeftNormal() const; void GetAveragePoint() const; void GetUnionOfAllLeftMaterials() const; - s32 GetCount() const; + s32 GetCount() const { return x0_list.size(); } void Swap(s32); - void Add(const CCollisionInfo&, bool); - void Clear(); - void End(); - void End() const; - void Begin(); - void Begin() const; + void Add(const CCollisionInfo& info, bool swap) + { + if (x0_list.size() == 32) + return; + if (!swap) + x0_list.push_back(info); + else + x0_list.push_back(info.GetSwapped()); + } + void Clear() { x0_list.clear(); } + rstl::reserved_vector::iterator end() { return x0_list.end(); } + rstl::reserved_vector::const_iterator end() const { return x0_list.end(); } + rstl::reserved_vector::iterator begin() { return x0_list.begin(); } + rstl::reserved_vector::const_iterator begin() const { return x0_list.begin(); } }; } diff --git a/Runtime/Collision/CCollisionPrimitive.cpp b/Runtime/Collision/CCollisionPrimitive.cpp index 279a30c72..2e1008289 100644 --- a/Runtime/Collision/CCollisionPrimitive.cpp +++ b/Runtime/Collision/CCollisionPrimitive.cpp @@ -2,18 +2,23 @@ #include "CInternalRayCastStructure.hpp" #include "CMaterialFilter.hpp" #include "InternalColliders.hpp" +#include "CCollisionInfoList.hpp" namespace urde { -std::unique_ptr> CCollisionPrimitive::sCollisionTypeList; -std::unique_ptr> CCollisionPrimitive::sTableOfCollidables; -std::unique_ptr> CCollisionPrimitive::sTableOfBooleanCollidables; -std::unique_ptr> CCollisionPrimitive::sTableOfMovingCollidables; s32 CCollisionPrimitive::sNumTypes = 0; +bool CCollisionPrimitive::sInitComplete = false; bool CCollisionPrimitive::sTypesAdded = false; bool CCollisionPrimitive::sTypesAdding = false; bool CCollisionPrimitive::sCollidersAdded = false; bool CCollisionPrimitive::sCollidersAdding = false; +std::unique_ptr> CCollisionPrimitive::sCollisionTypeList; +std::unique_ptr> CCollisionPrimitive::sTableOfCollidables; +std::unique_ptr> CCollisionPrimitive::sTableOfBooleanCollidables; +std::unique_ptr> CCollisionPrimitive::sTableOfMovingCollidables; +ComparisonFunc CCollisionPrimitive::sNullCollider = {}; +BooleanComparisonFunc CCollisionPrimitive::sNullBooleanCollider = {}; +MovingComparisonFunc CCollisionPrimitive::sNullMovingCollider = {}; CCollisionPrimitive::CCollisionPrimitive(const CMaterialList& list) : x8_material(list) {} void CCollisionPrimitive::SetMaterial(const CMaterialList& material) { x8_material = material; } @@ -26,6 +31,119 @@ CRayCastResult CCollisionPrimitive::CastRay(const zeus::CVector3f& start, const return CastRayInternal(CInternalRayCastStructure(start, dir, length, xf, filter)); } +bool CCollisionPrimitive::InternalCollide(const CInternalCollisionStructure& collision, + CCollisionInfoList& list) +{ + u32 idx0 = collision.GetLeft().GetPrim().GetTableIndex(); + u32 idx1 = collision.GetRight().GetPrim().GetTableIndex(); + + ComparisonFunc func; + if (idx0 == -1 || idx1 == -1) + { + sNullCollider = nullptr; + func = sNullCollider; + } + else + { + func = (*sTableOfCollidables)[sNumTypes * idx1 + idx0]; + } + + if (func) + { + if (!collision.GetLeft().GetFilter().Passes(collision.GetRight().GetPrim().GetMaterial()) || + !collision.GetRight().GetFilter().Passes(collision.GetLeft().GetPrim().GetMaterial())) + return false; + return func(collision, list); + } + + if (idx0 == -1 || idx1 == -1) + { + sNullCollider = nullptr; + func = sNullCollider; + } + else + { + func = (*sTableOfCollidables)[sNumTypes * idx0 + idx1]; + } + + if (func) + { + if (!collision.GetLeft().GetFilter().Passes(collision.GetRight().GetPrim().GetMaterial()) || + !collision.GetRight().GetFilter().Passes(collision.GetLeft().GetPrim().GetMaterial())) + return false; + CInternalCollisionStructure swappedCollision(collision.GetRight(), collision.GetLeft()); + u32 startListCount = list.GetCount(); + if (func(swappedCollision, list)) + { + for (auto it = list.begin() + startListCount ; it != list.end() ; ++it) + it->Swap(); + return true; + } + } + + return false; +} + +bool CCollisionPrimitive::Collide(CInternalCollisionStructure::CPrimDesc& prim0, + CInternalCollisionStructure::CPrimDesc& prim1, + CCollisionInfoList& list) +{ + return InternalCollide({prim0, prim1}, list); +} + +bool CCollisionPrimitive::InternalCollideBoolean(const CInternalCollisionStructure& collision) +{ + u32 idx0 = collision.GetLeft().GetPrim().GetTableIndex(); + u32 idx1 = collision.GetRight().GetPrim().GetTableIndex(); + + BooleanComparisonFunc func; + if (idx0 == -1 || idx1 == -1) + { + sNullBooleanCollider = nullptr; + func = sNullBooleanCollider; + } + else + { + func = (*sTableOfBooleanCollidables)[sNumTypes * idx1 + idx0]; + } + + if (func) + { + if (!collision.GetLeft().GetFilter().Passes(collision.GetRight().GetPrim().GetMaterial()) || + !collision.GetRight().GetFilter().Passes(collision.GetLeft().GetPrim().GetMaterial())) + return false; + return func(collision); + } + + if (idx0 == -1 || idx1 == -1) + { + sNullBooleanCollider = nullptr; + func = sNullBooleanCollider; + } + else + { + func = (*sTableOfBooleanCollidables)[sNumTypes * idx0 + idx1]; + } + + if (func) + { + if (!collision.GetLeft().GetFilter().Passes(collision.GetRight().GetPrim().GetMaterial()) || + !collision.GetRight().GetFilter().Passes(collision.GetLeft().GetPrim().GetMaterial())) + return false; + CInternalCollisionStructure swappedCollision(collision.GetRight(), collision.GetLeft()); + return func(swappedCollision); + } + + CCollisionInfoList list; + return InternalCollide(collision, list); +} + +bool CCollisionPrimitive::CollideBoolean(CInternalCollisionStructure::CPrimDesc& prim0, + CInternalCollisionStructure::CPrimDesc& prim1) +{ + return InternalCollideBoolean({prim0, prim1}); +} + void CCollisionPrimitive::InitBeginTypes() { sCollisionTypeList.reset(new std::vector()); @@ -37,67 +155,154 @@ void CCollisionPrimitive::InitBeginTypes() void CCollisionPrimitive::InitAddType(const CCollisionPrimitive::Type& tp) { tp.GetSetter()(sCollisionTypeList->size()); - - sCollisionTypeList->reserve(sCollisionTypeList->size() + 1); sCollisionTypeList->push_back(tp); } -void CCollisionPrimitive::InitEndTypes() { sTypesAdding = false; } +void CCollisionPrimitive::InitEndTypes() +{ + sCollisionTypeList->shrink_to_fit(); + sNumTypes = sCollisionTypeList->size(); + sTypesAdding = false; + sTypesAdded = true; +} void CCollisionPrimitive::InitBeginColliders() { sTableOfCollidables.reset(new std::vector()); sTableOfBooleanCollidables.reset(new std::vector()); sTableOfMovingCollidables.reset(new std::vector()); + size_t tableSz = sCollisionTypeList->size() * sCollisionTypeList->size(); + sTableOfCollidables->resize(tableSz); + sTableOfBooleanCollidables->resize(tableSz); + sTableOfMovingCollidables->resize(tableSz); sCollidersAdding = true; InternalColliders::AddColliders(); } void CCollisionPrimitive::InitAddBooleanCollider(const CCollisionPrimitive::BooleanComparison& cmp) { + int idx0 = -1; + for (int i=0 ; isize() ; ++i) + { + if (!strcmp(cmp.GetType1(), (*sCollisionTypeList)[i].GetInfo())) + { + idx0 = i; + break; + } + } + + int idx1 = -1; + for (int i=0 ; isize() ; ++i) + { + if (!strcmp(cmp.GetType2(), (*sCollisionTypeList)[i].GetInfo())) + { + idx1 = i; + break; + } + } + + if (idx0 < 0 || idx1 < 0 || idx0 >= sNumTypes || idx1 >= sNumTypes) + return; + + BooleanComparisonFunc& funcOut = + (idx0 == -1 || idx1 == -1) ? sNullBooleanCollider : (*sTableOfBooleanCollidables)[idx1 * sNumTypes + idx0]; + funcOut = cmp.GetCollider(); } -void CCollisionPrimitive::InitAddBooleanCollider(const BooleanComparisonFunc& cmp, const char* a, const char* b) +void CCollisionPrimitive::InitAddBooleanCollider(BooleanComparisonFunc cmp, const char* a, const char* b) { - InitAddBooleanCollider({std::move(cmp), a, b}); + InitAddBooleanCollider({cmp, a, b}); } -void CCollisionPrimitive::InitAddMovingCollider(const CCollisionPrimitive::MovingComparison& cmp) {} - -void CCollisionPrimitive::InitAddMovingCollider(const MovingComparisonFunc& cmp, const char* a, const char* b) +void CCollisionPrimitive::InitAddMovingCollider(const CCollisionPrimitive::MovingComparison& cmp) { - InitAddMovingCollider({std::move(cmp), a, b}); + int idx0 = -1; + for (int i=0 ; isize() ; ++i) + { + if (!strcmp(cmp.GetType1(), (*sCollisionTypeList)[i].GetInfo())) + { + idx0 = i; + break; + } + } + + int idx1 = -1; + for (int i=0 ; isize() ; ++i) + { + if (!strcmp(cmp.GetType2(), (*sCollisionTypeList)[i].GetInfo())) + { + idx1 = i; + break; + } + } + + if (idx0 < 0 || idx1 < 0 || idx0 >= sNumTypes || idx1 >= sNumTypes) + return; + + MovingComparisonFunc& funcOut = + (idx0 == -1 || idx1 == -1) ? sNullMovingCollider : (*sTableOfMovingCollidables)[idx1 * sNumTypes + idx0]; + funcOut = cmp.GetCollider(); +} + +void CCollisionPrimitive::InitAddMovingCollider(MovingComparisonFunc cmp, const char* a, const char* b) +{ + InitAddMovingCollider({cmp, a, b}); } void CCollisionPrimitive::InitAddCollider(const CCollisionPrimitive::Comparison& cmp) { + int idx0 = -1; + for (int i=0 ; isize() ; ++i) + { + if (!strcmp(cmp.GetType1(), (*sCollisionTypeList)[i].GetInfo())) + { + idx0 = i; + break; + } + } + + int idx1 = -1; + for (int i=0 ; isize() ; ++i) + { + if (!strcmp(cmp.GetType2(), (*sCollisionTypeList)[i].GetInfo())) + { + idx1 = i; + break; + } + } + + if (idx0 < 0 || idx1 < 0 || idx0 >= sNumTypes || idx1 >= sNumTypes) + return; + + ComparisonFunc& funcOut = + (idx0 == -1 || idx1 == -1) ? sNullCollider : (*sTableOfCollidables)[idx1 * sNumTypes + idx0]; + funcOut = cmp.GetCollider(); } -void CCollisionPrimitive::InitAddCollider(const ComparisonFunc& cmp, const char* a, const char* b) +void CCollisionPrimitive::InitAddCollider(ComparisonFunc cmp, const char* a, const char* b) { - InitAddCollider({std::move(cmp), a, b}); + InitAddCollider({cmp, a, b}); } void CCollisionPrimitive::InitEndColliders() { + sCollidersAdding = false; + sCollidersAdded = true; + sInitComplete = true; } -void CCollisionPrimitive::Unitialize() +void CCollisionPrimitive::Uninitialize() { + sInitComplete = false; sCollidersAdding = false; + sCollidersAdded = false; sTypesAdding = false; + sTypesAdded = false; + sNumTypes = 0; sCollisionTypeList.reset(); sTableOfCollidables.reset(); sTableOfMovingCollidables.reset(); sTableOfBooleanCollidables.reset(); } -CCollisionPrimitive::Type::Type(const std::function& setter, const char* info) -: x0_setter(setter), x4_info(info) -{ -} - -const char* CCollisionPrimitive::Type::GetInfo() const { return x4_info; } - -std::function CCollisionPrimitive::Type::GetSetter() const { return x0_setter; } } diff --git a/Runtime/Collision/CCollisionPrimitive.hpp b/Runtime/Collision/CCollisionPrimitive.hpp index ac05c14c8..70facf194 100644 --- a/Runtime/Collision/CCollisionPrimitive.hpp +++ b/Runtime/Collision/CCollisionPrimitive.hpp @@ -9,33 +9,60 @@ namespace urde { +class CCollisionPrimitive; +class CMaterialFilter; + +class CInternalCollisionStructure +{ +public: + class CPrimDesc + { + const CCollisionPrimitive& x0_prim; + const CMaterialFilter& x4_filter; + zeus::CTransform x8_xf; + public: + CPrimDesc(const CCollisionPrimitive& prim, const CMaterialFilter& filter, + const zeus::CTransform& xf) + : x0_prim(prim), x4_filter(filter), x8_xf(xf) {} + const CCollisionPrimitive& GetPrim() const { return x0_prim; } + const CMaterialFilter& GetFilter() const { return x4_filter; } + const zeus::CTransform& GetTransform() const { return x8_xf; } + }; +private: + CPrimDesc x0_p0; + CPrimDesc x38_p1; +public: + CInternalCollisionStructure(const CPrimDesc& p0, const CPrimDesc& p1) + : x0_p0(p0), x38_p1(p1) {} + const CPrimDesc& GetLeft() const { return x0_p0; } + const CPrimDesc& GetRight() const { return x38_p1; } +}; class COBBTree; -class CInternalCollisionStructure; class CCollisionInfo; class CCollisionInfoList; class CInternalRayCastStructure; -class CMaterialFilter; -using ComparisonFunc = std::function; -using MovingComparisonFunc = - std::function; -using BooleanComparisonFunc = std::function; +typedef bool(*ComparisonFunc)(const CInternalCollisionStructure&, CCollisionInfoList&); +typedef bool(*MovingComparisonFunc)(const CInternalCollisionStructure&, const zeus::CVector3f&, + double&, CCollisionInfo&); +typedef bool(*BooleanComparisonFunc)(const CInternalCollisionStructure&); +typedef void(*PrimitiveSetter)(u32); class CCollisionPrimitive { public: class Type { - std::function x0_setter; + PrimitiveSetter x0_setter; const char* x4_info; public: Type() = default; - Type(const std::function& setter, const char* info); + Type(PrimitiveSetter setter, const char* info) + : x0_setter(setter), x4_info(info) {} - const char* GetInfo() const; - - std::function GetSetter() const; + const char* GetInfo() const { return x4_info; } + PrimitiveSetter GetSetter() const { return x0_setter; } }; class Comparison @@ -45,12 +72,12 @@ public: const char* x8_type2; public: - Comparison(const ComparisonFunc& collider, const char* type1, const char* type2) + Comparison(ComparisonFunc collider, const char* type1, const char* type2) : x0_collider(collider), x4_type1(type1), x8_type2(type2) { } - const ComparisonFunc& GetCollider() const { return x0_collider; } + ComparisonFunc GetCollider() const { return x0_collider; } const char* GetType1() const { return x4_type1; } const char* GetType2() const { return x8_type2; } }; @@ -62,12 +89,12 @@ public: const char* x8_type2; public: - MovingComparison(const MovingComparisonFunc& collider, const char* type1, const char* type2) + MovingComparison(MovingComparisonFunc collider, const char* type1, const char* type2) : x0_collider(collider), x4_type1(type1), x8_type2(type2) { } - const MovingComparisonFunc& GetCollider() const { return x0_collider; } + MovingComparisonFunc GetCollider() const { return x0_collider; } const char* GetType1() const { return x4_type1; } const char* GetType2() const { return x8_type2; } }; @@ -79,26 +106,33 @@ public: const char* x8_type2; public: - BooleanComparison(const BooleanComparisonFunc& collider, const char* type1, const char* type2) + BooleanComparison(BooleanComparisonFunc collider, const char* type1, const char* type2) : x0_collider(collider), x4_type1(type1), x8_type2(type2) { } - const BooleanComparisonFunc& GetCollider() const { return x0_collider; } + BooleanComparisonFunc GetCollider() const { return x0_collider; } const char* GetType1() const { return x4_type1; } const char* GetType2() const { return x8_type2; } }; private: CMaterialList x8_material; - static std::unique_ptr> sCollisionTypeList; - static std::unique_ptr> sTableOfCollidables; - static std::unique_ptr> sTableOfBooleanCollidables; - static std::unique_ptr> sTableOfMovingCollidables; static s32 sNumTypes; + static bool sInitComplete; static bool sTypesAdded; static bool sTypesAdding; static bool sCollidersAdded; static bool sCollidersAdding; + static std::unique_ptr> sCollisionTypeList; + static std::unique_ptr> sTableOfCollidables; + static std::unique_ptr> sTableOfBooleanCollidables; + static std::unique_ptr> sTableOfMovingCollidables; + static ComparisonFunc sNullCollider; + static BooleanComparisonFunc sNullBooleanCollider; + static MovingComparisonFunc sNullMovingCollider; + + static bool InternalCollide(const CInternalCollisionStructure& collision, CCollisionInfoList& list); + static bool InternalCollideBoolean(const CInternalCollisionStructure& collision); public: CCollisionPrimitive() = default; @@ -114,20 +148,26 @@ public: CRayCastResult CastRay(const zeus::CVector3f& start, const zeus::CVector3f& dir, float length, const CMaterialFilter& filter, const zeus::CTransform& xf) const; + static bool Collide(CInternalCollisionStructure::CPrimDesc& prim0, + CInternalCollisionStructure::CPrimDesc& prim1, + CCollisionInfoList& list); + static bool CollideBoolean(CInternalCollisionStructure::CPrimDesc& prim0, + CInternalCollisionStructure::CPrimDesc& prim1); + static void InitBeginTypes(); static void InitAddType(const Type& tp); static void InitEndTypes(); static void InitBeginColliders(); static void InitAddBooleanCollider(const BooleanComparison& cmp); - static void InitAddBooleanCollider(const BooleanComparisonFunc&, const char*, const char*); + static void InitAddBooleanCollider(BooleanComparisonFunc, const char*, const char*); static void InitAddMovingCollider(const MovingComparison& cmp); - static void InitAddMovingCollider(const MovingComparisonFunc&, const char*, const char*); + static void InitAddMovingCollider(MovingComparisonFunc, const char*, const char*); static void InitAddCollider(const Comparison& cmp); - static void InitAddCollider(const ComparisonFunc&, const char*, const char*); + static void InitAddCollider(ComparisonFunc, const char*, const char*); static void InitEndColliders(); - static void Unitialize(); + static void Uninitialize(); }; } diff --git a/Runtime/Collision/CGameCollision.cpp b/Runtime/Collision/CGameCollision.cpp index 9090228eb..f4d32bb36 100644 --- a/Runtime/Collision/CGameCollision.cpp +++ b/Runtime/Collision/CGameCollision.cpp @@ -6,15 +6,24 @@ #include "CStateManager.hpp" #include "TCastTo.hpp" #include "World/CWorld.hpp" +#include "CAABoxFilter.hpp" +#include "CBallFilter.hpp" +#include "CMetroidAreaCollider.hpp" +#include "CollisionUtil.hpp" +#include "World/CScriptPlatform.hpp" +#include "CCollidableSphere.hpp" namespace urde { -float CollisionImpulseFiniteVsInfinite(float f1, float f2, float f3) { return f1 * ((1.f / f3) * f2); } - -float CollisionImpulseFiniteVsFinite(float f1, float f2, float f3, float f4) +static float CollisionImpulseFiniteVsInfinite(float mass, float velNormDot, float restitution) { - return (-(1.f + f4) * f3) / ((1.f / f1) + (1.f / f2)); + return mass * ((1.f / restitution) * velNormDot); +} + +static float CollisionImpulseFiniteVsFinite(float mass, float velNormDot, float restitution, float f4) +{ + return (-(1.f + f4) * restitution) / ((1.f / mass) + (1.f / velNormDot)); } void CGameCollision::InitCollision() @@ -47,9 +56,207 @@ void CGameCollision::InitCollision() CCollisionPrimitive::InitEndColliders(); } -void CGameCollision::Move(CStateManager& mgr, CPhysicsActor& actor, float dt, const rstl::reserved_vector*) +void CGameCollision::MovePlayer(CStateManager& mgr, CPhysicsActor& actor, float dt, + const rstl::reserved_vector* colliderList) { + actor.SetAngularEnabled(true); + actor.AddMotionState(actor.PredictAngularMotion(dt)); + if (actor.IsUseStandardCollider()) + { + MoveAndCollide(mgr, actor, dt, CBallFilter(actor), colliderList); + } + else + { + if (actor.GetMaterialList().HasMaterial(EMaterialTypes::GroundCollider)) + MoveGroundCollider_New(mgr, actor, dt, colliderList); + else + MoveAndCollide(mgr, actor, dt, CBallFilter(actor), colliderList); + } + actor.SetAngularEnabled(false); +} +void CGameCollision::MoveGroundCollider(CStateManager& mgr, CPhysicsActor& actor, float dt, + const rstl::reserved_vector* colliderList) +{ + CMotionState oldState = actor.GetMotionState(); + CMotionState newState = actor.PredictMotion_Internal(dt); + newState.x0_translation.magnitude(); + actor.GetMaterialFilter(); + zeus::CAABox motionVol = actor.GetMotionVolume(dt); + rstl::reserved_vector augmentedColliderList; + if (colliderList) + augmentedColliderList = *colliderList; + mgr.BuildColliderList(augmentedColliderList, actor, motionVol); + CAreaCollisionCache cache(motionVol); + actor.GetCollisionPrimitive()->GetPrimType(); + // TODO: finish +} + +void CGameCollision::MoveGroundCollider_New(CStateManager& mgr, CPhysicsActor& actor, float dt, + const rstl::reserved_vector* colliderList) +{ + // TODO: finish +} + +void CGameCollision::MoveAndCollide(CStateManager& mgr, CPhysicsActor& actor, float dt, const ICollisionFilter& filter, + const rstl::reserved_vector* colliderList) +{ + bool isPlayer = actor.GetMaterialList().HasMaterial(EMaterialTypes::Player); + bool r28 = false; + bool r27 = false; + int r26 = 0; + float f31 = dt; + float _4AC4 = dt; + float _4AC8 = dt; + CCollisionInfoList accumList; + CMotionState mState = actor.PredictMotion_Internal(dt); + float transMag = mState.x0_translation.magnitude(); + float m1 = 0.0005f / actor.GetCollisionAccuracyModifier(); + float m2 = transMag / (5.f * actor.GetCollisionAccuracyModifier()); + float mMax = std::max(m1, m2); + float m3 = 0.001f / actor.GetCollisionAccuracyModifier(); + + zeus::CAABox motionVol = actor.GetMotionVolume(dt); + rstl::reserved_vector useColliderList; + if (colliderList) + useColliderList = *colliderList; + else + mgr.BuildColliderList(useColliderList, actor, zeus::CAABox(motionVol.min - 1.f, motionVol.max + 1.f)); + CAreaCollisionCache cache(motionVol); + if (actor.GetCollisionPrimitive()->GetPrimType() != FOURCC('OBTG') && + !actor.GetMaterialFilter().GetExcludeList().HasMaterial(EMaterialTypes::ThirtyEight)) + { + BuildAreaCollisionCache(mgr, cache); + zeus::CVector3f pos = actor.GetCollisionPrimitive()->CalculateAABox(actor.GetPrimitiveTransform()).center(); + float halfExtent = 0.5f * GetMinExtentForCollisionPrimitive(*actor.GetCollisionPrimitive()); + if (transMag > halfExtent) + { + TUniqueId id = kInvalidUniqueId; + zeus::CVector3f dir = (1.f / transMag) * mState.x0_translation; + CRayCastResult intersectRes = mgr.RayWorldIntersection(id, pos, dir, transMag, + actor.GetMaterialFilter(), useColliderList); + if (intersectRes.IsValid()) + { + f31 = dt * (intersectRes.GetT() / transMag); + mState = actor.PredictMotion_Internal(f31); + _4AC8 = halfExtent * (dt / transMag); + mMax = std::min(mMax, halfExtent); + } + } + } + + float f27 = f31; + while (true) + { + actor.MoveCollisionPrimitive(mState.x0_translation); + if (DetectCollisionBoolean_Cached(mgr, cache, *actor.GetCollisionPrimitive(), + actor.GetPrimitiveTransform(), actor.GetMaterialFilter(), + useColliderList)) + { + r28 = true; + if (mState.x0_translation.magnitude() < mMax) + { + r27 = true; + accumList.Clear(); + TUniqueId id = kInvalidUniqueId; + DetectCollision_Cached(mgr, cache, *actor.GetCollisionPrimitive(), actor.GetPrimitiveTransform(), + actor.GetMaterialFilter(), useColliderList, id, accumList); + TCastToPtr otherActor = mgr.ObjectById(id); + actor.MoveCollisionPrimitive(zeus::CVector3f::skZero); + zeus::CVector3f relVel = GetActorRelativeVelocities(actor, otherActor.GetPtr()); + CCollisionInfoList filterList0, filterList1; + CollisionUtil::FilterOutBackfaces(relVel, accumList, filterList0); + if (filterList0.GetCount() > 0) + { + filter.Filter(filterList0, filterList1); + if (!filterList1.GetCount() && actor.GetMaterialList().HasMaterial(EMaterialTypes::Player)) + { + CMotionState mState = actor.GetLastNonCollidingState(); + mState.x1c_velocity *= 0.5f; + mState.x28_angularMomentum *= 0.5f; + actor.SetMotionState(mState); + } + } + MakeCollisionCallbacks(mgr, actor, id, filterList1); + SendScriptMessages(mgr, actor, otherActor.GetPtr(), filterList1); + ResolveCollisions(actor, otherActor.GetPtr(), filterList1); + _4AC4 -= f31; + f27 = std::min(_4AC4, _4AC8); + f31 = f27; + } + else + { + f27 *= 0.5f; + f31 *= 0.5f; + } + } + else + { + actor.AddMotionState(mState); + _4AC4 -= f31; + f31 = f27; + actor.ClearImpulses(); + actor.MoveCollisionPrimitive(zeus::CVector3f::skZero); + } + + ++r26; + if (_4AC4 > 0.f && ((mState.x0_translation.magnitude() > m3 && r27) || !r27) && r26 <= 1000) + mState = actor.PredictMotion_Internal(f31); + else + break; + } + + f27 = _4AC4 / dt; + if (!r28 && !actor.GetMaterialList().HasMaterial(EMaterialTypes::GroundCollider)) + mgr.SendScriptMsg(&actor, kInvalidUniqueId, EScriptObjectMessage::Falling); + + if (isPlayer) + CollisionFailsafe(mgr, cache, actor, *actor.GetCollisionPrimitive(), useColliderList, f27, 2); + + actor.ClearForcesAndTorques(); + actor.MoveCollisionPrimitive(zeus::CVector3f::skZero); +} + +zeus::CVector3f CGameCollision::GetActorRelativeVelocities(const CPhysicsActor& act0, const CPhysicsActor* act1) +{ + zeus::CVector3f ret = act0.GetVelocity(); + if (act1) + { + bool rider = false; + if (TCastToConstPtr plat = act1) + rider = plat->IsRider(act0.GetUniqueId()); + if (!rider) + ret =- act1->GetVelocity(); + } + return ret; +} + +void CGameCollision::Move(CStateManager& mgr, CPhysicsActor& actor, float dt, + const rstl::reserved_vector* colliderList) +{ + if (!actor.IsMovable()) + return; + if (actor.GetMaterialList().HasMaterial(EMaterialTypes::GroundCollider) || actor.WillMove(mgr)) + { + if (actor.IsAngularEnabled()) + actor.AddMotionState(actor.PredictAngularMotion(dt)); + actor.UseCollisionImpulses(); + if (actor.GetMaterialList().HasMaterial(EMaterialTypes::Solid)) + { + if (actor.GetMaterialList().HasMaterial(EMaterialTypes::Player)) + MovePlayer(mgr, actor, dt, colliderList); + else if (actor.GetMaterialList().HasMaterial(EMaterialTypes::GroundCollider)) + MoveGroundCollider(mgr, actor, dt, colliderList); + else + MoveAndCollide(mgr, actor, dt, CAABoxFilter(actor), colliderList); + } + else + { + actor.AddMotionState(actor.PredictMotion_Internal(dt)); + actor.ClearForcesAndTorques(); + } + mgr.UpdateActorInSortedLists(actor); + } } bool CGameCollision::CanBlock(const CMaterialList& mat, const zeus::CVector3f& v) @@ -213,4 +420,417 @@ bool CGameCollision::RayStaticIntersectionArea(const CGameArea& area, const zeus zeus::CLine line(pos, dir); return node.LineTest(line, filter, mag); } + +void CGameCollision::BuildAreaCollisionCache(CStateManager& mgr, CAreaCollisionCache& cache) +{ + cache.ClearCache(); + for (const CGameArea& area : *mgr.GetWorld()) + { + const CAreaOctTree& areaCollision = *area.GetPostConstructed()->x0_collision; + CMetroidAreaCollider::COctreeLeafCache octreeCache(areaCollision); + CMetroidAreaCollider::BuildOctreeLeafCache(areaCollision.GetRootNode(), + cache.GetCacheBounds(), octreeCache); + cache.AddOctreeLeafCache(octreeCache); + } +} + +float CGameCollision::GetMinExtentForCollisionPrimitive(const CCollisionPrimitive& prim) +{ + if (prim.GetPrimType() == FOURCC('SPHR')) + { + const CCollidableSphere& sphere = static_cast(prim); + return 2.f * sphere.GetSphere().radius; + } + else if (prim.GetPrimType() == FOURCC('AABX')) + { + const CCollidableAABox& aabx = static_cast(prim); + zeus::CVector3f extent = aabx.GetAABB().max - aabx.GetAABB().min; + float minExtent = std::min(extent.x, extent.y); + minExtent = std::min(minExtent, extent.z); + return minExtent; + } + else if (prim.GetPrimType() == FOURCC('ABSH')) + { + // Combination AABB / Sphere cut from game + } + return 1.f; +} + +bool CGameCollision::DetectCollisionBoolean_Cached(CStateManager& mgr, CAreaCollisionCache& cache, + const CCollisionPrimitive& prim, const zeus::CTransform& xf, + const CMaterialFilter& filter, + const rstl::reserved_vector& nearList) +{ + if (!filter.GetExcludeList().HasMaterial(EMaterialTypes::ThirtyEight) && + DetectStaticCollisionBoolean_Cached(mgr, cache, prim, xf, filter)) + return true; + if (DetectDynamicCollisionBoolean(prim, xf, nearList, mgr)) + return true; + return false; +} + +bool CGameCollision::DetectStaticCollisionBoolean(CStateManager& mgr, const CCollisionPrimitive& prim, + const zeus::CTransform& xf, const CMaterialFilter& filter) +{ + if (prim.GetPrimType() == FOURCC('OBTG')) + return false; + + if (prim.GetPrimType() == FOURCC('AABX')) + { + zeus::CAABox aabb = prim.CalculateAABox(xf); + for (const CGameArea& area : *mgr.GetWorld()) + { + if (CMetroidAreaCollider::AABoxCollisionCheckBoolean( + *area.GetPostConstructed()->x0_collision, aabb, filter)) + return true; + } + } + else if (prim.GetPrimType() == FOURCC('SPHR')) + { + const CCollidableSphere& sphere = static_cast(prim); + zeus::CAABox aabb = prim.CalculateAABox(xf); + zeus::CSphere xfSphere = sphere.Transform(xf); + for (const CGameArea& area : *mgr.GetWorld()) + { + if (CMetroidAreaCollider::SphereCollisionCheckBoolean( + *area.GetPostConstructed()->x0_collision, aabb, xfSphere, filter)) + return true; + } + } + else if (prim.GetPrimType() == FOURCC('ABSH')) + { + // Combination AABB / Sphere cut from game + } + + return false; +} + +bool CGameCollision::DetectStaticCollisionBoolean_Cached(CStateManager& mgr, CAreaCollisionCache& cache, + const CCollisionPrimitive& prim, const zeus::CTransform& xf, + const CMaterialFilter& filter) +{ + if (prim.GetPrimType() == FOURCC('OBTG')) + return false; + + zeus::CAABox aabb = prim.CalculateAABox(xf); + if (!aabb.inside(cache.GetCacheBounds())) + { + zeus::CAABox newAABB(aabb.min - 0.2f, aabb.max + 0.2f); + newAABB.accumulateBounds(cache.GetCacheBounds()); + cache.SetCacheBounds(newAABB); + BuildAreaCollisionCache(mgr, cache); + } + + if (cache.HasCacheOverflowed()) + return DetectStaticCollisionBoolean(mgr, prim, xf, filter); + + if (prim.GetPrimType() == FOURCC('AABX')) + { + for (CMetroidAreaCollider::COctreeLeafCache& leafCache : cache) + if (CMetroidAreaCollider::AABoxCollisionCheckBoolean_Cached(leafCache, aabb, filter)) + return true; + } + else if (prim.GetPrimType() == FOURCC('SPHR')) + { + const CCollidableSphere& sphere = static_cast(prim); + zeus::CSphere xfSphere = sphere.Transform(xf); + for (CMetroidAreaCollider::COctreeLeafCache& leafCache : cache) + if (CMetroidAreaCollider::SphereCollisionCheckBoolean_Cached(leafCache, aabb, xfSphere, filter)) + return true; + } + else if (prim.GetPrimType() == FOURCC('ABSH')) + { + // Combination AABB / Sphere cut from game + } + + return false; +} + +bool CGameCollision::DetectDynamicCollisionBoolean(const CCollisionPrimitive& prim, const zeus::CTransform& xf, + const rstl::reserved_vector& nearList, + CStateManager& mgr) +{ + for (TUniqueId id : nearList) + { + if (TCastToPtr actor = mgr.ObjectById(id)) + { + CInternalCollisionStructure::CPrimDesc p0(prim, CMaterialFilter::skPassEverything, xf); + CInternalCollisionStructure::CPrimDesc p1(*actor->GetCollisionPrimitive(), + CMaterialFilter::skPassEverything, + actor->GetPrimitiveTransform()); + if (CCollisionPrimitive::CollideBoolean(p0, p1)) + return true; + } + } + + return false; +} + +bool CGameCollision::DetectCollision_Cached(CStateManager& mgr, CAreaCollisionCache& cache, + const CCollisionPrimitive& prim, const zeus::CTransform& xf, + const CMaterialFilter& filter, + const rstl::reserved_vector& nearList, + TUniqueId& idOut, CCollisionInfoList& infoList) +{ + bool ret = false; + if (!filter.GetExcludeList().HasMaterial(EMaterialTypes::ThirtyEight)) + if (DetectStaticCollision_Cached(mgr, cache, prim, xf, filter, infoList)) + ret = true; + + TUniqueId id = kInvalidUniqueId; + if (DetectDynamicCollision(prim, xf, nearList, id, infoList, mgr)) + { + ret = true; + idOut = id; + } + + return ret; +} + +bool CGameCollision::DetectStaticCollision(CStateManager& mgr, const CCollisionPrimitive& prim, + const zeus::CTransform& xf, const CMaterialFilter& filter, + CCollisionInfoList& list) +{ + if (prim.GetPrimType() == FOURCC('OBTG')) + return false; + + if (prim.GetPrimType() == FOURCC('AABX')) + { + zeus::CAABox aabb = prim.CalculateAABox(xf); + for (const CGameArea& area : *mgr.GetWorld()) + { + if (CMetroidAreaCollider::AABoxCollisionCheck( + *area.GetPostConstructed()->x0_collision, aabb, filter, + prim.GetMaterial(), list)) + return true; + } + } + else if (prim.GetPrimType() == FOURCC('SPHR')) + { + const CCollidableSphere& sphere = static_cast(prim); + zeus::CAABox aabb = prim.CalculateAABox(xf); + zeus::CSphere xfSphere = sphere.Transform(xf); + for (const CGameArea& area : *mgr.GetWorld()) + { + if (CMetroidAreaCollider::SphereCollisionCheck( + *area.GetPostConstructed()->x0_collision, aabb, xfSphere, + prim.GetMaterial(), filter, list)) + return true; + } + } + else if (prim.GetPrimType() == FOURCC('ABSH')) + { + // Combination AABB / Sphere cut from game + } + + return false; +} + +bool CGameCollision::DetectStaticCollision_Cached(CStateManager& mgr, CAreaCollisionCache& cache, + const CCollisionPrimitive& prim, const zeus::CTransform& xf, + const CMaterialFilter& filter, CCollisionInfoList& list) +{ + if (prim.GetPrimType() == FOURCC('OBTG')) + return false; + + zeus::CAABox calcAABB = prim.CalculateAABox(xf); + if (!calcAABB.inside(cache.GetCacheBounds())) + { + zeus::CAABox newAABB(calcAABB.min - 0.2f, calcAABB.max + 0.2f); + newAABB.accumulateBounds(cache.GetCacheBounds()); + cache.SetCacheBounds(newAABB); + BuildAreaCollisionCache(mgr, cache); + } + + if (cache.HasCacheOverflowed()) + return DetectStaticCollision(mgr, prim, xf, filter, list); + + if (prim.GetPrimType() == FOURCC('AABX')) + { + for (CMetroidAreaCollider::COctreeLeafCache& leafCache : cache) + if (CMetroidAreaCollider::AABoxCollisionCheck_Cached(leafCache, calcAABB, filter, + prim.GetMaterial(), list)) + return true; + } + else if (prim.GetPrimType() == FOURCC('SPHR')) + { + const CCollidableSphere& sphere = static_cast(prim); + zeus::CSphere xfSphere = sphere.Transform(xf); + for (CMetroidAreaCollider::COctreeLeafCache& leafCache : cache) + if (CMetroidAreaCollider::SphereCollisionCheck_Cached(leafCache, calcAABB, xfSphere, + prim.GetMaterial(), filter, list)) + return true; + } + else if (prim.GetPrimType() == FOURCC('ABSH')) + { + // Combination AABB / Sphere cut from game + } + + return false; +} + +bool CGameCollision::DetectDynamicCollision(const CCollisionPrimitive& prim, const zeus::CTransform& xf, + const rstl::reserved_vector& nearList, + TUniqueId& idOut, CCollisionInfoList& list, CStateManager& mgr) +{ + for (TUniqueId id : nearList) + { + if (TCastToPtr actor = mgr.ObjectById(id)) + { + CInternalCollisionStructure::CPrimDesc p0(prim, CMaterialFilter::skPassEverything, xf); + CInternalCollisionStructure::CPrimDesc p1(*actor->GetCollisionPrimitive(), + CMaterialFilter::skPassEverything, + actor->GetPrimitiveTransform()); + if (CCollisionPrimitive::Collide(p0, p1, list)) + { + idOut = actor->GetUniqueId(); + return true; + } + } + } + + return false; +} + +void CGameCollision::MakeCollisionCallbacks(CStateManager& mgr, CPhysicsActor& actor, + TUniqueId id, const CCollisionInfoList& list) +{ + actor.CollidedWith(id, list, mgr); + if (id != kInvalidUniqueId) + { + if (TCastToPtr actor = mgr.ObjectById(id)) + { + CCollisionInfoList swappedList = list; + for (CCollisionInfo& info : swappedList) + info.Swap(); + actor->CollidedWith(actor->GetUniqueId(), list, mgr); + } + } +} + +void CGameCollision::SendScriptMessages(CStateManager& mgr, CActor& a0, CActor* a1, const CCollisionInfoList& list) +{ + bool onFloor = false; + bool platform = false; + bool platform2 = false; + for (const CCollisionInfo& info : list) + { + if (IsFloor(info.GetMaterialLeft(), info.GetNormalLeft())) + { + onFloor = true; + if (info.GetMaterialLeft().HasMaterial(EMaterialTypes::Platform)) + platform = true; + SendMaterialMessage(mgr, info.GetMaterialLeft(), a0); + } + } + + if (onFloor) + { + mgr.SendScriptMsg(&a0, kInvalidUniqueId, EScriptObjectMessage::OnFloor); + if (platform) + { + if (TCastToPtr plat = a1) + { + mgr.SendScriptMsg(plat.GetPtr(), a0.GetUniqueId(), + EScriptObjectMessage::AddPlatformRider); + } + } + else if (a1) + { + if (TCastToPtr plat = a0) + { + for (const CCollisionInfo& info : list) + { + if (IsFloor(info.GetMaterialRight(), info.GetNormalRight())) + { + if (info.GetMaterialRight().HasMaterial(EMaterialTypes::Platform)) + platform2 = true; + SendMaterialMessage(mgr, info.GetMaterialLeft(), a0); + } + } + if (platform2) + { + mgr.SendScriptMsg(plat.GetPtr(), a1->GetUniqueId(), + EScriptObjectMessage::AddPlatformRider); + } + } + } + } +} + +void CGameCollision::ResolveCollisions(CPhysicsActor& a0, CPhysicsActor* a1, const CCollisionInfoList& list) +{ + for (const CCollisionInfo& info : list) + { + CCollisionInfo infoCopy = info; + float restitution = GetCoefficientOfRestitution(infoCopy) + a0.GetCoefficientOfRestitutionModifier(); + if (a1) + { + CollideWithDynamicBodyNoRot(a0, *a1, infoCopy, restitution, false); + } + else + { + CollideWithStaticBodyNoRot(a0, infoCopy.GetMaterialLeft(), infoCopy.GetMaterialRight(), + infoCopy.GetNormalLeft(), restitution, false); + } + } +} + +void CGameCollision::CollideWithDynamicBodyNoRot(CPhysicsActor& a0, CPhysicsActor& a1, + const CCollisionInfo& info, float restitution, bool) +{ + /* TODO: Finish */ +} + +void CGameCollision::CollideWithStaticBodyNoRot(CPhysicsActor& a0, const CMaterialList& m0, const CMaterialList& m1, + const zeus::CUnitVector3f& normal, float restitution, bool b) +{ + zeus::CUnitVector3f useNorm = normal; + if (b && m0.HasMaterial(EMaterialTypes::Player) && !m1.HasMaterial(EMaterialTypes::Floor)) + useNorm.z = 0.f; + + if (useNorm.canBeNormalized()) + { + useNorm.normalize(); + float velNormDot = a0.GetVelocity().dot(useNorm); + if (velNormDot < 0.0001f) + { + a0.ApplyImpulseWR( + useNorm * CollisionImpulseFiniteVsInfinite(a0.GetMass(), velNormDot, restitution), + zeus::CAxisAngle::sIdentity); + a0.UseCollisionImpulses(); + } + else if (velNormDot < 0.001f) + { + a0.ApplyImpulseWR(0.05f * a0.GetMass() * useNorm, zeus::CAxisAngle::sIdentity); + a0.UseCollisionImpulses(); + } + } +} + +void CGameCollision::CollisionFailsafe(CStateManager& mgr, CAreaCollisionCache& cache, + CPhysicsActor& actor, const CCollisionPrimitive& prim, + const rstl::reserved_vector& nearList, + float f1, u32 failsafeTicks) +{ + actor.MoveCollisionPrimitive(zeus::CVector3f::skZero); + if (f1 > 0.5f) + actor.SetNumTicksPartialUpdate(actor.GetNumTicksPartialUpdate() + 1); + + if (actor.GetNumTicksPartialUpdate() > 1 || + DetectCollisionBoolean_Cached(mgr, cache, prim, actor.GetPrimitiveTransform(), + actor.GetMaterialFilter(), nearList)) + { + actor.SetNumTicksPartialUpdate(0); + actor.SetNumTicksStuck(actor.GetNumTicksStuck() + 1); + if (actor.GetNumTicksStuck() < failsafeTicks) + return; + /* TODO: Finish */ + } + else + { + actor.SetLastNonCollidingState(actor.GetMotionState()); + actor.SetNumTicksStuck(0); + } +} } diff --git a/Runtime/Collision/CGameCollision.hpp b/Runtime/Collision/CGameCollision.hpp index 102d98b24..0118b36d2 100644 --- a/Runtime/Collision/CGameCollision.hpp +++ b/Runtime/Collision/CGameCollision.hpp @@ -5,14 +5,12 @@ #include "rstl.hpp" #include "RetroTypes.hpp" #include "CRayCastResult.hpp" +#include "CMetroidAreaCollider.hpp" +#include "CCollisionPrimitive.hpp" namespace urde { -class CInternalCollisionStructure -{ -}; - class CActor; class CCollisionInfo; class CCollisionInfoList; @@ -21,10 +19,21 @@ class CStateManager; class CPhysicsActor; class CMaterialFilter; class CGameArea; +class ICollisionFilter; class CGameCollision { + static void MovePlayer(CStateManager& mgr, CPhysicsActor& actor, float dt, + const rstl::reserved_vector* colliderList); + static void MoveGroundCollider(CStateManager& mgr, CPhysicsActor& actor, float dt, + const rstl::reserved_vector* colliderList); + static void MoveGroundCollider_New(CStateManager& mgr, CPhysicsActor& actor, float dt, + const rstl::reserved_vector* colliderList); + static void MoveAndCollide(CStateManager& mgr, CPhysicsActor& actor, float dt, const ICollisionFilter& filter, + const rstl::reserved_vector* colliderList); + static zeus::CVector3f GetActorRelativeVelocities(const CPhysicsActor& act0, const CPhysicsActor* act1); public: + static float GetCoefficientOfRestitution(const CCollisionInfo&) { return 0.f; } static bool NullMovingCollider(const CInternalCollisionStructure&, const zeus::CVector3f&, double&, CCollisionInfo&) { return false; @@ -32,11 +41,12 @@ public: static bool NullBooleanCollider(const CInternalCollisionStructure&) { return false; } static bool NullCollisionCollider(const CInternalCollisionStructure&, CCollisionInfoList&) { return false; } static void InitCollision(); - static void Move(CStateManager& mgr, CPhysicsActor& actor, float dt, const rstl::reserved_vector*); + static void Move(CStateManager& mgr, CPhysicsActor& actor, float dt, + const rstl::reserved_vector* colliderList); static bool CanBlock(const CMaterialList&, const zeus::CVector3f&); static bool IsFloor(const CMaterialList&, const zeus::CVector3f&); - void SendMaterialMessage(CStateManager&, const CMaterialList&, CActor&); + static void SendMaterialMessage(CStateManager&, const CMaterialList&, CActor&); static CRayCastResult RayStaticIntersection(const CStateManager& mgr, const zeus::CVector3f& pos, const zeus::CVector3f& dir, float mag, const CMaterialFilter& filter); static bool RayStaticIntersectionBool(const CStateManager& mgr, const zeus::CVector3f& start, @@ -55,6 +65,46 @@ public: const rstl::reserved_vector& nearList); static bool RayStaticIntersectionArea(const CGameArea& area, const zeus::CVector3f& pos, const zeus::CVector3f& dir, float mag, const CMaterialFilter& filter); + static void BuildAreaCollisionCache(CStateManager& mgr, CAreaCollisionCache& cache); + static float GetMinExtentForCollisionPrimitive(const CCollisionPrimitive& prim); + static bool DetectCollisionBoolean_Cached(CStateManager& mgr, CAreaCollisionCache& cache, + const CCollisionPrimitive& prim, const zeus::CTransform& xf, + const CMaterialFilter& filter, + const rstl::reserved_vector& nearList); + static bool DetectStaticCollisionBoolean(CStateManager& mgr, const CCollisionPrimitive& prim, + const zeus::CTransform& xf, const CMaterialFilter& filter); + static bool DetectStaticCollisionBoolean_Cached(CStateManager& mgr, CAreaCollisionCache& cache, + const CCollisionPrimitive& prim, const zeus::CTransform& xf, + const CMaterialFilter& filter); + static bool DetectDynamicCollisionBoolean(const CCollisionPrimitive& prim, const zeus::CTransform& xf, + const rstl::reserved_vector& nearList, + CStateManager& mgr); + static bool DetectCollision_Cached(CStateManager& mgr, CAreaCollisionCache& cache, + const CCollisionPrimitive& prim, const zeus::CTransform& xf, + const CMaterialFilter& filter, + const rstl::reserved_vector& nearList, + TUniqueId& idOut, CCollisionInfoList& infoList); + static bool DetectStaticCollision(CStateManager& mgr, const CCollisionPrimitive& prim, + const zeus::CTransform& xf, const CMaterialFilter& filter, + CCollisionInfoList& list); + static bool DetectStaticCollision_Cached(CStateManager& mgr, CAreaCollisionCache& cache, + const CCollisionPrimitive& prim, const zeus::CTransform& xf, + const CMaterialFilter& filter, CCollisionInfoList& list); + static bool DetectDynamicCollision(const CCollisionPrimitive& prim, const zeus::CTransform& xf, + const rstl::reserved_vector& nearList, + TUniqueId& idOut, CCollisionInfoList& list, CStateManager& mgr); + static void MakeCollisionCallbacks(CStateManager& mgr, CPhysicsActor& actor, TUniqueId id, + const CCollisionInfoList& list); + static void SendScriptMessages(CStateManager& mgr, CActor& a0, CActor* a1, const CCollisionInfoList& list); + static void ResolveCollisions(CPhysicsActor& a0, CPhysicsActor* a1, const CCollisionInfoList& list); + static void CollideWithDynamicBodyNoRot(CPhysicsActor& a0, CPhysicsActor& a1, const CCollisionInfo& info, + float restitution, bool); + static void CollideWithStaticBodyNoRot(CPhysicsActor& a0, const CMaterialList& m0, const CMaterialList& m1, + const zeus::CUnitVector3f& normal, float restitution, bool); + static void CollisionFailsafe(CStateManager& mgr, CAreaCollisionCache& cache, + CPhysicsActor& actor, const CCollisionPrimitive& prim, + const rstl::reserved_vector& nearList, + float, u32 failsafeTicks); }; } diff --git a/Runtime/Collision/CMakeLists.txt b/Runtime/Collision/CMakeLists.txt index 6b8b3291e..33ce3e4a9 100644 --- a/Runtime/Collision/CMakeLists.txt +++ b/Runtime/Collision/CMakeLists.txt @@ -22,6 +22,9 @@ set(COLLISION_SOURCES CRayCastResult.hpp CRayCastResult.cpp CCollisionActor.hpp CCollisionActor.cpp CCollisionActorManager.hpp CCollisionActorManager.cpp - CJointCollisionDescription.hpp CJointCollisionDescription.cpp) + CJointCollisionDescription.hpp CJointCollisionDescription.cpp + CAABoxFilter.hpp CAABoxFilter.cpp + CBallFilter.hpp CBallFilter.cpp + ICollisionFilter.hpp) runtime_add_list(Collision COLLISION_SOURCES) diff --git a/Runtime/Collision/CMetroidAreaCollider.cpp b/Runtime/Collision/CMetroidAreaCollider.cpp index e69de29bb..a01021285 100644 --- a/Runtime/Collision/CMetroidAreaCollider.cpp +++ b/Runtime/Collision/CMetroidAreaCollider.cpp @@ -0,0 +1,121 @@ +#include "CMetroidAreaCollider.hpp" + +namespace urde +{ + +CMetroidAreaCollider::COctreeLeafCache::COctreeLeafCache(const CAreaOctTree& octTree) +: x0_octTree(octTree) +{ + x908_24_overflow = false; +} + +void CMetroidAreaCollider::COctreeLeafCache::AddLeaf(const CAreaOctTree::Node& node) +{ + if (x4_nodeCache.size() == 64) + { + x908_24_overflow = true; + return; + } + + x4_nodeCache.push_back(node); +} + +void CMetroidAreaCollider::BuildOctreeLeafCache(const CAreaOctTree::Node& node, const zeus::CAABox& aabb, + CMetroidAreaCollider::COctreeLeafCache& cache) +{ + for (int i=0 ; i<8 ; ++i) + { + u16 flags = (node.GetChildFlags() >> (i * 2)) & 0x3; + if (flags) + { + CAreaOctTree::Node ch = node.GetChild(i); + if (aabb.intersects(ch.GetBoundingBox())) + { + if (flags == 0x2) + cache.AddLeaf(ch); + else + BuildOctreeLeafCache(ch, aabb, cache); + } + } + } +} + +bool CMetroidAreaCollider::AABoxCollisionCheckBoolean_Cached(const COctreeLeafCache& leafCache, const zeus::CAABox& aabb, + const CMaterialFilter& filter) +{ + return false; +} + +bool CMetroidAreaCollider::AABoxCollisionCheckBoolean(const CAreaOctTree& octTree, const zeus::CAABox& aabb, + const CMaterialFilter& filter) +{ + return false; +} + +bool CMetroidAreaCollider::SphereCollisionCheckBoolean_Cached(const COctreeLeafCache& leafCache, const zeus::CAABox& aabb, + const zeus::CSphere& sphere, const CMaterialFilter& filter) +{ + return false; +} + +bool CMetroidAreaCollider::SphereCollisionCheckBoolean(const CAreaOctTree& octTree, const zeus::CAABox& aabb, + const zeus::CSphere& sphere, const CMaterialFilter& filter) +{ + return false; +} + +bool CMetroidAreaCollider::AABoxCollisionCheck_Cached(const COctreeLeafCache& leafCache, const zeus::CAABox& aabb, + const CMaterialFilter& filter, const CMaterialList& matList, + CCollisionInfoList& list) +{ + return false; +} + +bool CMetroidAreaCollider::AABoxCollisionCheck(const CAreaOctTree& octTree, const zeus::CAABox& aabb, + const CMaterialFilter& filter, const CMaterialList& matList, + CCollisionInfoList& list) +{ + return false; +} + +bool CMetroidAreaCollider::SphereCollisionCheck_Cached(const COctreeLeafCache& leafCache, const zeus::CAABox& aabb, + const zeus::CSphere& sphere, const CMaterialList& matList, + const CMaterialFilter& filter, CCollisionInfoList& list) +{ + return false; +} + +bool CMetroidAreaCollider::SphereCollisionCheck(const CAreaOctTree& octTree, const zeus::CAABox& aabb, + const zeus::CSphere& sphere, const CMaterialList& matList, + const CMaterialFilter& filter, CCollisionInfoList& list) +{ + return false; +} + +void CAreaCollisionCache::ClearCache() +{ + x18_leafCaches.clear(); + x1b40_24_leafOverflow = false; + x1b40_25_cacheOverflow = false; +} + +void CAreaCollisionCache::AddOctreeLeafCache(const CMetroidAreaCollider::COctreeLeafCache& leafCache) +{ + if (!leafCache.GetNumLeaves()) + return; + + if (leafCache.HasCacheOverflowed()) + x1b40_24_leafOverflow = true; + + if (x18_leafCaches.size() < 3) + { + x18_leafCaches.push_back(leafCache); + } + else + { + x1b40_24_leafOverflow = true; + x1b40_25_cacheOverflow = true; + } +} + +} diff --git a/Runtime/Collision/CMetroidAreaCollider.hpp b/Runtime/Collision/CMetroidAreaCollider.hpp index 146b4374f..0ed953e8e 100644 --- a/Runtime/Collision/CMetroidAreaCollider.hpp +++ b/Runtime/Collision/CMetroidAreaCollider.hpp @@ -1,13 +1,78 @@ #ifndef __URDE_CMETROIDAREACOLLIDER_HPP__ #define __URDE_CMETROIDAREACOLLIDER_HPP__ +#include "RetroTypes.hpp" +#include "zeus/CAABox.hpp" +#include "CAreaOctTree.hpp" + namespace urde { +class CCollisionInfoList; +class CMaterialList; class CMetroidAreaCollider { public: - CMetroidAreaCollider(); + class COctreeLeafCache + { + const CAreaOctTree& x0_octTree; + rstl::reserved_vector x4_nodeCache; + bool x908_24_overflow : 1; + public: + COctreeLeafCache(const CAreaOctTree& octTree); + void AddLeaf(const CAreaOctTree::Node& node); + u32 GetNumLeaves() const { return x4_nodeCache.size(); } + bool HasCacheOverflowed() const { return x908_24_overflow; } + }; + static void BuildOctreeLeafCache(const CAreaOctTree::Node& root, const zeus::CAABox& aabb, + CMetroidAreaCollider::COctreeLeafCache& cache); + static bool AABoxCollisionCheckBoolean_Cached(const COctreeLeafCache& leafCache, const zeus::CAABox& aabb, + const CMaterialFilter& filter); + static bool AABoxCollisionCheckBoolean(const CAreaOctTree& octTree, const zeus::CAABox& aabb, + const CMaterialFilter& filter); + static bool SphereCollisionCheckBoolean_Cached(const COctreeLeafCache& leafCache, const zeus::CAABox& aabb, + const zeus::CSphere& sphere, const CMaterialFilter& filter); + static bool SphereCollisionCheckBoolean(const CAreaOctTree& octTree, const zeus::CAABox& aabb, + const zeus::CSphere& sphere, const CMaterialFilter& filter); + + static bool AABoxCollisionCheck_Cached(const COctreeLeafCache& leafCache, const zeus::CAABox& aabb, + const CMaterialFilter& filter, const CMaterialList& matList, + CCollisionInfoList& list); + static bool AABoxCollisionCheck(const CAreaOctTree& octTree, const zeus::CAABox& aabb, + const CMaterialFilter& filter, const CMaterialList& matList, + CCollisionInfoList& list); + static bool SphereCollisionCheck_Cached(const COctreeLeafCache& leafCache, const zeus::CAABox& aabb, + const zeus::CSphere& sphere, const CMaterialList& matList, + const CMaterialFilter& filter, CCollisionInfoList& list); + static bool SphereCollisionCheck(const CAreaOctTree& octTree, const zeus::CAABox& aabb, + const zeus::CSphere& sphere, const CMaterialList& matList, + const CMaterialFilter& filter, CCollisionInfoList& list); +}; + +class CAreaCollisionCache +{ + zeus::CAABox x0_aabb; + rstl::reserved_vector x18_leafCaches; + union + { + struct + { + bool x1b40_24_leafOverflow : 1; + bool x1b40_25_cacheOverflow : 1; + }; + u32 _dummy = 0; + }; +public: + CAreaCollisionCache(const zeus::CAABox& aabb) : x0_aabb(aabb) {} + void ClearCache(); + const zeus::CAABox& GetCacheBounds() const { return x0_aabb; } + void SetCacheBounds(const zeus::CAABox& aabb) { x0_aabb = aabb; } + void AddOctreeLeafCache(const CMetroidAreaCollider::COctreeLeafCache& leafCache); + u32 GetNumCaches() const { return x18_leafCaches.size(); } + const CMetroidAreaCollider::COctreeLeafCache& GetOctreeLeafCache(int idx) { return x18_leafCaches[idx]; } + bool HasCacheOverflowed() const { return x1b40_24_leafOverflow; } + rstl::reserved_vector::iterator begin() { return x18_leafCaches.begin(); } + rstl::reserved_vector::iterator end() { return x18_leafCaches.end(); } }; } diff --git a/Runtime/Collision/CollisionUtil.cpp b/Runtime/Collision/CollisionUtil.cpp index 388abcff0..a30a0fc2c 100644 --- a/Runtime/Collision/CollisionUtil.cpp +++ b/Runtime/Collision/CollisionUtil.cpp @@ -1,8 +1,12 @@ #include "CollisionUtil.hpp" +#include "CCollisionInfo.hpp" +#include "CCollisionInfoList.hpp" + namespace urde { namespace CollisionUtil { + bool LineIntersectsOBBox(const zeus::COBBox& obb, const zeus::CMRay& ray, float& d) { const zeus::CVector3f transXf = obb.transform.toMatrix4f().vec[0].toVec3f(); @@ -42,5 +46,56 @@ bool RaySphereIntersection(const zeus::CSphere& sphere, const zeus::CVector3f& p return false; } +void FilterOutBackfaces(const zeus::CVector3f& vec, const CCollisionInfoList& in, CCollisionInfoList& out) +{ + if (vec.canBeNormalized()) + { + zeus::CVector3f norm = vec.normalized(); + for (const CCollisionInfo& info : in) + { + if (info.GetNormalLeft().dot(norm) < 0.001f) + out.Add(info, false); + } + } + else + { + out = in; + } +} + +static const zeus::CVector3f AABBNormalTable[] = +{ + {-1.f, 0.f, 0.f}, + {1.f, 0.f, 0.f}, + {0.f, -1.f, 0.f}, + {0.f, 1.f, 0.f}, + {0.f, 0.f, -1.f}, + {0.f, 0.f, 1.f} +}; + +bool AABoxAABoxIntersection(const zeus::CAABox& aabb0, const CMaterialList& list0, + const zeus::CAABox& aabb1, const CMaterialList& list1, + CCollisionInfoList& infoList) +{ + zeus::CAABox boolAABB = aabb0.booleanIntersection(aabb1); + if (boolAABB.invalid()) + return false; + + /* TODO: Finish */ + + if (!infoList.GetCount()) + { + infoList.Add(CCollisionInfo(boolAABB, list0, list1, AABBNormalTable[4], -AABBNormalTable[4]), false); + infoList.Add(CCollisionInfo(boolAABB, list0, list1, AABBNormalTable[5], -AABBNormalTable[5]), false); + } + + return true; +} + +bool AABoxAABoxIntersection(const zeus::CAABox& aabb0, const zeus::CAABox& aabb1) +{ + return aabb0.intersects(aabb1); +} + } } diff --git a/Runtime/Collision/CollisionUtil.hpp b/Runtime/Collision/CollisionUtil.hpp index 7a859786f..433f493e2 100644 --- a/Runtime/Collision/CollisionUtil.hpp +++ b/Runtime/Collision/CollisionUtil.hpp @@ -3,15 +3,23 @@ #include "GCNTypes.hpp" #include "zeus/zeus.hpp" +#include "CMaterialList.hpp" namespace urde { +class CCollisionInfoList; namespace CollisionUtil { bool LineIntersectsOBBox(const zeus::COBBox&, const zeus::CMRay&, float&); u32 RayAABoxIntersection(const zeus::CMRay&, const zeus::CAABox&, const zeus::CVector3f&, float&); u32 RaySphereIntersection_Double(const zeus::CSphere&, const zeus::CVector3f&, const zeus::CVector3f&, double&); -bool RaySphereIntersection(const zeus::CSphere&, const zeus::CVector3f&, const zeus::CVector3f&, float, float&, zeus::CVector3f&); +bool RaySphereIntersection(const zeus::CSphere& sphere, const zeus::CVector3f& pos, const zeus::CVector3f& dir, + float mag, float& T, zeus::CVector3f& point); +void FilterOutBackfaces(const zeus::CVector3f& vec, const CCollisionInfoList& in, CCollisionInfoList& out); +bool AABoxAABoxIntersection(const zeus::CAABox& aabb0, const CMaterialList& list0, + const zeus::CAABox& aabb1, const CMaterialList& list1, + CCollisionInfoList& infoList); +bool AABoxAABoxIntersection(const zeus::CAABox& aabb0, const zeus::CAABox& aabb1); } } #endif // __URDE_COLLISIONUTIL_HPP__ diff --git a/Runtime/Collision/ICollisionFilter.hpp b/Runtime/Collision/ICollisionFilter.hpp new file mode 100644 index 000000000..2f8fcd36e --- /dev/null +++ b/Runtime/Collision/ICollisionFilter.hpp @@ -0,0 +1,21 @@ +#ifndef __URDE_ICOLLISIONFILTER_HPP__ +#define __URDE_ICOLLISIONFILTER_HPP__ + +#include "CCollisionInfoList.hpp" + +namespace urde +{ +class CActor; + +class ICollisionFilter +{ + CActor& x4_actor; +protected: + ICollisionFilter(CActor& actor) : x4_actor(actor) {} +public: + virtual void Filter(const CCollisionInfoList& in, CCollisionInfoList& out) const = 0; +}; + +} + +#endif // __URDE_ICOLLISIONFILTER_HPP__ diff --git a/Runtime/Weapon/CGrappleArm.hpp b/Runtime/Weapon/CGrappleArm.hpp index 6051b17dd..f1b60bacc 100644 --- a/Runtime/Weapon/CGrappleArm.hpp +++ b/Runtime/Weapon/CGrappleArm.hpp @@ -11,10 +11,11 @@ namespace urde class CGrappleArm { CModelData x0_modelData; - + zeus::CTransform x220_; public: CGrappleArm(const zeus::CVector3f& vec); void AsyncLoadSuit(CStateManager& mgr); + void SetX220(const zeus::CTransform& xf) { x220_ = xf; } }; } diff --git a/Runtime/Weapon/CPlayerGun.hpp b/Runtime/Weapon/CPlayerGun.hpp index 780fe7bb2..560d66f7a 100644 --- a/Runtime/Weapon/CPlayerGun.hpp +++ b/Runtime/Weapon/CPlayerGun.hpp @@ -219,6 +219,8 @@ public: u32 GetSelectedBeam() const { return x310_selectedBeam; } u32 GetPendingSelectedBeam() const { return x314_pendingSelectedBeam; } const CGunMorph& GetGunMorph() const { return x678_morph; } + void SetX3e8(const zeus::CTransform& xf) { x3e8_ = xf; } + CGrappleArm& GetGrappleArm() { return *x740_grappleArm; } }; } diff --git a/Runtime/World/CActor.cpp b/Runtime/World/CActor.cpp index 57434c755..3a70a3775 100644 --- a/Runtime/World/CActor.cpp +++ b/Runtime/World/CActor.cpp @@ -496,4 +496,12 @@ const CScannableObjectInfo* CActor::GetScannableObjectInfo() const return info.GetObj(); } + +void CActor::SetCalculateLighting(bool c) +{ + if (!x90_actorLights) + x90_actorLights = std::make_unique(8, zeus::CVector3f::skZero, + 4, 4, false, false, false, 0.1f); + xe4_31_lightsDirty = c; +} } diff --git a/Runtime/World/CActor.hpp b/Runtime/World/CActor.hpp index 921c5c721..99d6d0593 100644 --- a/Runtime/World/CActor.hpp +++ b/Runtime/World/CActor.hpp @@ -170,6 +170,7 @@ public: const CScannableObjectInfo* GetScannableObjectInfo() const; const CHealthInfo* GetHealthInfo() const { return const_cast(this)->HealthInfo(); } bool GetDoTargetDistanceTest() const { return xe7_30_doTargetDistanceTest; } + void SetCalculateLighting(bool c); }; } diff --git a/Runtime/World/CPhysicsActor.cpp b/Runtime/World/CPhysicsActor.cpp index 215013e78..4b630b2d5 100644 --- a/Runtime/World/CPhysicsActor.cpp +++ b/Runtime/World/CPhysicsActor.cpp @@ -12,12 +12,11 @@ CPhysicsActor::CPhysicsActor(TUniqueId uid, bool active, const std::string& name , xec_massRecip(moverData.x30_mass <= 0.f ? 1.f : 1.f / moverData.x30_mass) , x150_momentum(moverData.x18_momentum) , x1c0_collisionPrimitive(box, matList) -, x1f4_translation(xf.origin) -, x200_orientation(xf.buildMatrix3f()) +, x1f4_lastNonCollidingState(xf.origin, xf.buildMatrix3f()) , x23c_stepUpHeight(stepUp) , x240_stepDownHeight(stepDown) { - xf8_24_ = true; + xf8_24_movable = true; SetMass(moverData.x30_mass); MoveCollisionPrimitive(zeus::CVector3f::skZero); SetVelocityOR(moverData.x0_velocity); @@ -37,7 +36,7 @@ zeus::CVector3f CPhysicsActor::GetAimPosition(const CStateManager&, float dt) co return GetBoundingBox().center() + trans; } -void CPhysicsActor::CollidedWith(const TUniqueId&, const CCollisionInfoList&, CStateManager&) {} +void CPhysicsActor::CollidedWith(TUniqueId, const CCollisionInfoList&, CStateManager&) {} const CCollisionPrimitive* CPhysicsActor::GetCollisionPrimitive() const { return &x1c0_collisionPrimitive; } @@ -52,9 +51,9 @@ float CPhysicsActor::GetStepDownHeight() const { return x240_stepDownHeight; } float CPhysicsActor::GetWeight() const { return 24.525002f * xe8_mass; } -void CPhysicsActor::sub_8011A4C(float f) { x238_ = f; } +void CPhysicsActor::sub_8011A4C(float f) { x238_maximumCollisionVelocity = f; } -float CPhysicsActor::sub_8011A4B8() const { return x238_; } +float CPhysicsActor::sub_8011A4B8() const { return x238_maximumCollisionVelocity; } void CPhysicsActor::SetPrimitiveOffset(const zeus::CVector2f& offset) { x1e8_primitiveOffset = offset; } @@ -144,11 +143,6 @@ void CPhysicsActor::SetInertiaTensorScalar(float tensor) xf4_inertiaTensorRecip = 1.0f / tensor; } -void CPhysicsActor::SetCoefficientOfRestitutionModifier(float mod) -{ - x244_restitutionCoefModifier = mod; -} - void CPhysicsActor::SetMass(float mass) { xe8_mass = mass; @@ -302,7 +296,7 @@ CPhysicsState CPhysicsActor::GetPhysicsState() const CMotionState CPhysicsActor::PredictMotion_Internal(float dt) const { - if (xf8_25_) + if (xf8_25_angularEnabled) return PredictMotion(dt); CMotionState msl = PredictLinearMotion(dt); diff --git a/Runtime/World/CPhysicsActor.hpp b/Runtime/World/CPhysicsActor.hpp index a91fd26af..10c71ae89 100644 --- a/Runtime/World/CPhysicsActor.hpp +++ b/Runtime/World/CPhysicsActor.hpp @@ -29,8 +29,10 @@ struct CMotionState CMotionState(const zeus::CVector3f& origin, const zeus::CNUQuaternion& orientation, const zeus::CVector3f& velocity, const zeus::CAxisAngle& angle) : x0_translation(origin), xc_orientation(orientation), x1c_velocity(velocity), x28_angularMomentum(angle) - { - } + {} + CMotionState(const zeus::CVector3f& origin, const zeus::CNUQuaternion& orientation) + : x0_translation(origin), xc_orientation(orientation) + {} }; class CPhysicsState @@ -84,12 +86,12 @@ protected: union { struct { - bool xf8_24_ : 1; - bool xf8_25_ : 1; + bool xf8_24_movable : 1; + bool xf8_25_angularEnabled : 1; }; u8 _dummy = 0; }; - bool xf9_ = false; + bool xf9_standardCollider = false; zeus::CVector3f xfc_constantForce; zeus::CAxisAngle x108_angularMomentum; zeus::CMatrix3f x114_; @@ -105,18 +107,15 @@ protected: zeus::CAABox x1a4_baseBoundingBox; CCollidableAABox x1c0_collisionPrimitive; zeus::CVector3f x1e8_primitiveOffset; - zeus::CVector3f x1f4_translation; - zeus::CNUQuaternion x200_orientation; - zeus::CAxisAngle x210_; - zeus::CAxisAngle x21c_; + CMotionState x1f4_lastNonCollidingState; bool x234_ = false; - float x238_ = 1000000.0f; + float x238_maximumCollisionVelocity = 1000000.0f; float x23c_stepUpHeight; float x240_stepDownHeight; float x244_restitutionCoefModifier = 0.f; float x248_collisionAccuracyModifier = 1.f; - u32 x24c_; - u32 x250_; + u32 x24c_numTicksStuck; + u32 x250_numTicksPartialUpdate; public: CPhysicsActor(TUniqueId, bool, const std::string&, const CEntityInfo&, const zeus::CTransform&, CModelData&&, @@ -127,7 +126,7 @@ public: zeus::CVector3f GetAimPosition(const CStateManager&, float val) const; virtual const CCollisionPrimitive* GetCollisionPrimitive() const; virtual zeus::CTransform GetPrimitiveTransform() const; - virtual void CollidedWith(const TUniqueId&, const CCollisionInfoList&, CStateManager&); + virtual void CollidedWith(TUniqueId, const CCollisionInfoList&, CStateManager&); virtual float GetStepUpHeight() const; virtual float GetStepDownHeight() const; virtual float GetWeight() const; @@ -145,15 +144,19 @@ public: const zeus::CAABox& GetBaseBoundingBox() const; void AddMotionState(const CMotionState& mst); CMotionState GetMotionState() const; + const CMotionState& GetLastNonCollidingState() const { return x1f4_lastNonCollidingState; } + void SetLastNonCollidingState(const CMotionState& mst) { x1f4_lastNonCollidingState = mst; } void SetMotionState(const CMotionState& mst); + float GetMaximumCollisionVelocity() const { return x238_maximumCollisionVelocity; } + void SetMaximumCollisionVelocity(float v) { x238_maximumCollisionVelocity = v; } void SetInertiaTensorScalar(float tensor); - void SetCoefficientOfRestitutionModifier(float); void SetMass(float mass); void SetAngularVelocityOR(const zeus::CAxisAngle& angVel); zeus::CAxisAngle GetAngularVelocityOR() const; void SetAngularVelocityWR(const zeus::CAxisAngle& angVel); void SetVelocityWR(const zeus::CVector3f& vel); void SetVelocityOR(const zeus::CVector3f& vel); + const zeus::CVector3f& GetVelocity() const { return x138_velocity; } zeus::CVector3f GetTotalForcesWR() const; void RotateInOneFrameOR(const zeus::CQuaternion& q, float d); void MoveInOneFrameOR(const zeus::CVector3f& trans, float d); @@ -170,6 +173,19 @@ public: bool WillMove(const CStateManager&); void SetPhysicsState(const CPhysicsState& state); CPhysicsState GetPhysicsState() const; + bool IsMovable() const { return xf8_24_movable; } + void SetMovable(bool m) { xf8_24_movable = m; } + bool IsAngularEnabled() const { return xf8_25_angularEnabled; } + void SetAngularEnabled(bool e) { xf8_25_angularEnabled = e; } + float GetCollisionAccuracyModifier() const { return x248_collisionAccuracyModifier; } + void SetCollisionAccuracyModifier(float m) { x248_collisionAccuracyModifier = m; } + float GetCoefficientOfRestitutionModifier() const { return x244_restitutionCoefModifier; } + void SetCoefficientOfRestitutionModifier(float m) { x244_restitutionCoefModifier = m; } + bool IsUseStandardCollider() const { return xf9_standardCollider; } + u32 GetNumTicksPartialUpdate() const { return x250_numTicksPartialUpdate; } + void SetNumTicksPartialUpdate(u32 t) { x250_numTicksPartialUpdate = t; } + u32 GetNumTicksStuck() const { return x24c_numTicksStuck; } + void SetNumTicksStuck(u32 t) { x24c_numTicksStuck = t; } CMotionState PredictMotion_Internal(float) const; CMotionState PredictMotion(float dt) const; diff --git a/Runtime/World/CPlayer.cpp b/Runtime/World/CPlayer.cpp index 2cbbf2955..6ac712fff 100644 --- a/Runtime/World/CPlayer.cpp +++ b/Runtime/World/CPlayer.cpp @@ -24,7 +24,7 @@ static CModelData MakePlayerAnimRes(ResId resId, const zeus::CVector3f& scale) return {CAnimRes(resId, 0, scale, 0, true), 1}; } -CPlayer::CPlayer(TUniqueId uid, const zeus::CTransform& xf, const zeus::CAABox& aabb, unsigned int resId, +CPlayer::CPlayer(TUniqueId uid, const zeus::CTransform& xf, const zeus::CAABox& aabb, ResId resId, const zeus::CVector3f& playerScale, float mass, float stepUp, float stepDown, float f4, const CMaterialList& ml) : CPhysicsActor(uid, true, "CPlayer", CEntityInfo(kInvalidAreaId, CEntity::NullConnectionList), xf, @@ -34,7 +34,6 @@ CPlayer::CPlayer(TUniqueId uid, const zeus::CTransform& xf, const zeus::CAABox& x490_gun.reset(new CPlayerGun(uid)); x49c_gunNotFiringTimeout = g_tweakPlayerGun->GetGunNotFiringTime(); x4a0_inputFilter.reset(new CInputFilter()); - x768_morphball.reset(new CMorphBall(*this, f4)); x76c_cameraBob.reset(new CPlayerCameraBob(CPlayerCameraBob::ECameraBobType::One, zeus::CVector2f{CPlayerCameraBob::kCameraBobExtentX, CPlayerCameraBob::kCameraBobExtentY}, @@ -43,8 +42,43 @@ CPlayer::CPlayer(TUniqueId uid, const zeus::CTransform& xf, const zeus::CAABox& x9c4_27_ = true; x9c4_28_ = true; x9c5_31_ = true; - ResId beamId = g_tweakPlayerRes->GetBeamBallTransitionModel(x7ec_); + ResId beamId = g_tweakPlayerRes->GetBeamBallTransitionModel(x7ec_beam); x7f0_ballTransitionBeamModel = std::make_unique(CStaticRes(beamId, playerScale)); + x730_.reserve(3); + x768_morphball.reset(new CMorphBall(*this, f4)); + + SetInertiaTensorScalar(xe8_mass); + x1f4_lastNonCollidingState = GetMotionState(); + x490_gun->SetX3e8(x34_transform); + x490_gun->GetGrappleArm().SetX220(x34_transform); + + InitializeBallTransition(); + zeus::CAABox ballTransAABB = x64_modelData->GetBounds(); + x2f0_ballTransHeight = ballTransAABB.max.z - ballTransAABB.min.z; + + SetCalculateLighting(true); + + x90_actorLights->SetCastShadows(true); + x50c_.z = 0.f; + if (x50c_.canBeNormalized()) + x50c_.normalize(); + x2b4_.push_back(20.f); + x2b4_.push_back(80.f); + x2b4_.push_back(80.f); + x2b4_.push_back(270.f); + SetMaximumCollisionVelocity(25.f); + x354_onScreenOrbitObjects.reserve(64); + x344_nearbyOrbitObjects.reserve(64); + x364_offScreenOrbitObjects.reserve(64); + x64_modelData->SetScale(playerScale); + x7f0_ballTransitionBeamModel->SetScale(playerScale); + LoadAnimationTokens(); +} + +void CPlayer::InitializeBallTransition() +{ + if (x64_modelData && x64_modelData->HasAnimData()) + x64_modelData->AnimationData()->SetAnimation(CAnimPlaybackParms(2, -1, 1.f, true), false); } bool CPlayer::IsTransparent() const { return x588_alpha < 1.f; } @@ -246,7 +280,7 @@ void CPlayer::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CState { switch (msg) { - case EScriptObjectMessage::OnGround: + case EScriptObjectMessage::OnFloor: if (x258_movementState != EPlayerMovementState::OnGround && x2f8_morphTransState != EPlayerMorphBallState::Morphed && x300_fallingTime > 0.3f) @@ -834,7 +868,7 @@ const CCollisionPrimitive* CPlayer::GetCollisionPrimitive() const { return CPhys zeus::CTransform CPlayer::GetPrimitiveTransform() const { return {}; } -bool CPlayer::CollidedWith(TUniqueId, const CCollisionInfoList&, CStateManager& mgr) { return false; } +void CPlayer::CollidedWith(TUniqueId, const CCollisionInfoList&, CStateManager& mgr) {} float CPlayer::GetActualFirstPersonMaxVelocity() const { return 0.f; } diff --git a/Runtime/World/CPlayer.hpp b/Runtime/World/CPlayer.hpp index 638e9482b..beb7c021d 100644 --- a/Runtime/World/CPlayer.hpp +++ b/Runtime/World/CPlayer.hpp @@ -178,11 +178,11 @@ private: float x2a8_ = 1000.f; EPlayerMovementSurface x2ac_movementSurface = EPlayerMovementSurface::Normal; u32 x2b0_ = 2; - u32 x2b4_ = 0; + rstl::reserved_vector x2b4_; u32 x2d0_ = 3; float x2d4_ = 0.f; zeus::CAABox x2d8_; - float x2f0_ = 0.f; + float x2f0_ballTransHeight = 0.f; EPlayerCameraState x2f4_cameraState = EPlayerCameraState::Zero; EPlayerMorphBallState x2f8_morphTransState = EPlayerMorphBallState::Unmorphed; u32 x2fc_ = 0; @@ -247,7 +247,14 @@ private: u32 x4a4_ = 0; float x4f8_ = 0.f; float x4fc_ = 0.f; - float x53c_ = 0.f; + zeus::CVector3f x500_ = x34_transform.basis[1]; + zeus::CVector3f x50c_ = x34_transform.basis[1]; + zeus::CVector3f x518_ = x34_transform.basis[1]; + zeus::CVector3f x524_ = x34_transform.basis[1]; + zeus::CVector3f x530_ = x34_transform.basis[1]; + zeus::CVector3f x53c_ = x34_transform.basis[1]; + zeus::CVector3f x548_ = x34_transform.basis[1]; + float x554_ = x34_transform.basis[1].x; bool x558_ = false; float x55c_ = 0.f; float x560_ = 0.f; @@ -287,7 +294,7 @@ private: CVisorSteam x7a0_visorSteam = CVisorSteam(0.f, 0.f, 0.f, -1); ResId x7cc_ = -1; CAnimRes x7d0_animRes; - CPlayerState::EBeamId x7ec_ = CPlayerState::EBeamId::Power; + CPlayerState::EBeamId x7ec_beam = CPlayerState::EBeamId::Power; std::unique_ptr x7f0_ballTransitionBeamModel; zeus::CTransform x7f4_; float x824_ = 0.f; @@ -365,9 +372,10 @@ private: void ProcessFrozenInput(float dt, CStateManager& mgr); bool CheckSubmerged() const; void UpdateSubmerged(CStateManager& mgr); + void InitializeBallTransition(); public: - CPlayer(TUniqueId, const zeus::CTransform&, const zeus::CAABox&, unsigned int w1, const zeus::CVector3f&, float, float, + CPlayer(TUniqueId, const zeus::CTransform&, const zeus::CAABox&, ResId w1, const zeus::CVector3f&, float, float, float, float, const CMaterialList&); bool IsTransparent() const; @@ -493,7 +501,7 @@ public: zeus::CTransform CreateTransformFromMovementDirection() const; const CCollisionPrimitive* GetCollisionPrimitive() const; zeus::CTransform GetPrimitiveTransform() const; - bool CollidedWith(TUniqueId, const CCollisionInfoList&, CStateManager& mgr); + void CollidedWith(TUniqueId, const CCollisionInfoList&, CStateManager& mgr); float GetActualFirstPersonMaxVelocity() const; void SetMoveState(EPlayerMovementState, CStateManager& mgr); float JumpInput(const CFinalInput& input, CStateManager& mgr); diff --git a/Runtime/World/CScriptPlatform.cpp b/Runtime/World/CScriptPlatform.cpp index f41abfb3d..ff254de70 100644 --- a/Runtime/World/CScriptPlatform.cpp +++ b/Runtime/World/CScriptPlatform.cpp @@ -45,4 +45,12 @@ rstl::optional_object CScriptPlatform::GetTouchBounds() const return {CPhysicsActor::GetBoundingBox()}; } + +bool CScriptPlatform::IsRider(TUniqueId id) const +{ + for (const SRiders& rider : x318_riders) + if (rider.x0_uid == id) + return true; + return false; +} } diff --git a/Runtime/World/CScriptPlatform.hpp b/Runtime/World/CScriptPlatform.hpp index 984cf3ff8..e1f2457a5 100644 --- a/Runtime/World/CScriptPlatform.hpp +++ b/Runtime/World/CScriptPlatform.hpp @@ -65,6 +65,7 @@ public: void Accept(IVisitor& visitor); rstl::optional_object GetTouchBounds() const; + bool IsRider(TUniqueId id) const; }; } diff --git a/Runtime/World/ScriptObjectSupport.hpp b/Runtime/World/ScriptObjectSupport.hpp index cbe973a76..b9c192c47 100644 --- a/Runtime/World/ScriptObjectSupport.hpp +++ b/Runtime/World/ScriptObjectSupport.hpp @@ -200,7 +200,7 @@ enum class EScriptObjectMessage Play = 20, Alert = 21, InternalMessage00 = 22, - OnGround = 23, + OnFloor = 23, InternalMessage02 = 24, InternalMessage03 = 25, Falling = 26,