diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a8d3711..15439421 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,7 +195,7 @@ set(SPT_SOURCES FetchContent_Declare( monocle GIT_REPOSITORY https://github.com/UncraftedName/Monocle - GIT_TAG 3ff422cc2a7d4048369c1cae7b1315155e9afa08 + GIT_TAG cf2d275f0b63c9294ec217141f9e5e19492f3192 ) FetchContent_MakeAvailable(monocle) diff --git a/spt/features/visualizations/monocle/mon_feature.hpp b/spt/features/visualizations/monocle/mon_feature.hpp index 122e558a..e95371d3 100644 --- a/spt/features/visualizations/monocle/mon_feature.hpp +++ b/spt/features/visualizations/monocle/mon_feature.hpp @@ -8,6 +8,7 @@ #include "spt\feature.hpp" +#include "thirdparty\monocle_implicit_conversions.hpp" #include "teleport_chain\generate.hpp" #include @@ -84,13 +85,7 @@ struct WorkerMonocleData mon::PlacementOrder order, mon::GameVersion gv, const mon::TeleportChainParams& paramsTemplate) - : pp(*(mon::Vector*)&bluePos, - *(mon::QAngle*)&blueAng, - *(mon::Vector*)&orangePos, - *(mon::QAngle*)&orangeAng, - order, - gv) - , paramsTemplate(paramsTemplate) + : pp(bluePos, blueAng, orangePos, orangeAng, order, gv), paramsTemplate(paramsTemplate) { this->paramsTemplate.pp = &pp; } @@ -220,8 +215,7 @@ class MonocleWorker return img.size; } - mon::Vector PixelToWorldCoordinates(WorkerPixel px, - const mon::TeleportChainParams* paramsOverride = nullptr) const; + Vector PixelToWorldCoordinates(WorkerPixel px, const mon::TeleportChainParams* paramsOverride = nullptr) const; std::optional GetPixelResult(WorkerPixel px) const { diff --git a/spt/features/visualizations/monocle/mon_imgui.cpp b/spt/features/visualizations/monocle/mon_imgui.cpp index 9719a4f7..77e3c6ad 100644 --- a/spt/features/visualizations/monocle/mon_imgui.cpp +++ b/spt/features/visualizations/monocle/mon_imgui.cpp @@ -616,10 +616,10 @@ bool MonocleFeature::CheckPortalsChanged(const utils::PortalInfo* newEntryPortal auto& oldEntry = oldMonData->paramsTemplate.EntryPortal(); auto& oldExit = oldMonData->paramsTemplate.ExitPortal(); - auto vec_match = [](auto& a, auto& b) { return *(Vector*)&a == *(Vector*)&b; }; - return !vec_match(oldEntry.pos, newEntryPortal->pos) || !vec_match(oldExit.pos, newLinkedPortal->pos) - || !vec_match(oldEntry.ang, newEntryPortal->ang) || !vec_match(oldExit.ang, newLinkedPortal->ang); + return (const Vector&)oldEntry.pos != newEntryPortal->pos || (const Vector&)oldExit.pos != newLinkedPortal->pos + || (const QAngle&)oldEntry.ang != newEntryPortal->ang + || (const QAngle&)oldExit.ang != newLinkedPortal->ang; } void MonocleFeature::RestartWorkers(const utils::PortalInfo* newEntryPortal) @@ -639,10 +639,10 @@ void MonocleFeature::RestartWorkers(const utils::PortalInfo* newEntryPortal) mon::TeleportChainParams paramsTemplate; - mon::Vector entCenter = *(mon::Vector*)&newEntryPortal->pos; + auto& entCenter = newEntryPortal->pos; paramsTemplate.ent = imguiPersist.usePlayer - ? mon::Entity::CreatePlayerFromCenter(entCenter, imguiPersist.combos.playerCrouched.Grab()) + ? mon::Entity::CreatePlayerFromCenter(newEntryPortal->pos, imguiPersist.combos.playerCrouched.Grab()) : mon::Entity::CreateBall(entCenter, imguiPersist.nonPlayerRadius); paramsTemplate.first_tp_from_blue = !newEntryPortal->isOrange; paramsTemplate.record_flags = mon::TCRF_NONE; diff --git a/spt/features/visualizations/monocle/mon_worker.cpp b/spt/features/visualizations/monocle/mon_worker.cpp index 168805e6..0e6c371c 100644 --- a/spt/features/visualizations/monocle/mon_worker.cpp +++ b/spt/features/visualizations/monocle/mon_worker.cpp @@ -19,14 +19,14 @@ MonocleWorker::~MonocleWorker() thread.join(); } -mon::Vector MonocleWorker::PixelToWorldCoordinates(WorkerPixel px, const mon::TeleportChainParams* paramsOverride) const +Vector MonocleWorker::PixelToWorldCoordinates(WorkerPixel px, const mon::TeleportChainParams* paramsOverride) const { Assert(!!monocleData); const mon::TeleportChainParams* params = paramsOverride ? paramsOverride : &monocleData->paramsTemplate; const mon::Portal& p = params->EntryPortal(); // center on each pixel and orient as if we're looking at the portal - mon::Vector uShift = p.u * (mon::PORTAL_HALF_HEIGHT * ((2 * px.y + 1) / (float)img.size.y - 1)); - mon::Vector rShift = p.r * (mon::PORTAL_HALF_WIDTH * ((2 * px.x + 1) / (float)img.size.x - 1)); + Vector uShift = p.u * (mon::PORTAL_HALF_HEIGHT * ((2 * px.y + 1) / (float)img.size.y - 1)); + Vector rShift = p.r * (mon::PORTAL_HALF_WIDTH * ((2 * px.x + 1) / (float)img.size.x - 1)); return (p.pos - uShift) - rShift; } @@ -229,53 +229,52 @@ void MonocleWorker::RecomputeEffectiveTpSpace() * The player will always be teleported when their center is on the portal plane. To figure * out the effective teleport space: * - slice the player using the portal plane to create a 2D polygon - * - create an AABB of that polygon + * - create a 2D AABB of that polygon * - "subtract" that AABB from the portal rectangle */ matrix3x4_t portalToWorld; - AngleIMatrix(*(QAngle*)&p.ang, *(Vector*)&p.pos, portalToWorld); + AngleIMatrix(p.ang, p.pos, portalToWorld); // create an AABB centered at the portal mon::Entity centeredEnt = ent.WithNewCenter(p.pos); - mon::Vector mins = centeredEnt.GetWorldMins(); - mon::Vector maxs = centeredEnt.GetWorldMaxs(); // get a cross section of the player sliced by the portal plane (world space) std::array edgeIntersectionsWorldSpace; size_t intersectionCount = 0; - auto checkPlaneIntersectLine = [&](const Vector& a, const Vector& b) + auto checkPortalPlaneIntersectLineSegment = [&](const Vector& a, const Vector& b) { - const VPlane& portalPlane = *(VPlane*)&p.plane; - float aDotN = a.Dot(portalPlane.m_Normal); - float bDotN = b.Dot(portalPlane.m_Normal); + float aDotN = a.Dot(p.plane.n); + float bDotN = b.Dot(p.plane.n); // t is the fraction at which the line segment a->b intersects the portal plane - float t = (portalPlane.m_Dist - aDotN) / (bDotN - aDotN); + float t = (p.plane.d - aDotN) / (bDotN - aDotN); // because of this epsilon, we may sometimes get false positives and include more edges than necessary (up to 10) if (t >= -0.0001f && t <= 1.0001f) edgeIntersectionsWorldSpace[intersectionCount++] = Lerp(t, a, b); }; - // iterate over all player AABB edges - - // edges from the mins corner - checkPlaneIntersectLine(*(Vector*)&mins, {maxs.x, mins.y, mins.z}); - checkPlaneIntersectLine(*(Vector*)&mins, {mins.x, maxs.y, mins.z}); - checkPlaneIntersectLine(*(Vector*)&mins, {mins.x, mins.y, maxs.z}); - - // the other 9 edges :) - for (size_t r = 0; r < 3; r++) - { - Vector from = *(Vector*)&maxs; - from[r] = mins[r]; - for (size_t flipAx = 0; flipAx < 3; flipAx++) - { - Vector to = from; - to[flipAx] = r == flipAx ? maxs[flipAx] : mins[flipAx]; - checkPlaneIntersectLine(from, to); - } - } + // iterate over all player AABB edges - pick 4 reference corners and change each of the 3 axes one at a time (mins<->maxs) to get an adjacent corner + + Vector a = centeredEnt.GetWorldMins(); + Vector b = centeredEnt.GetWorldMaxs(); + + Vector ref = {a.x, a.y, a.z}; + checkPortalPlaneIntersectLineSegment(ref, {b.x, a.y, a.z}); + checkPortalPlaneIntersectLineSegment(ref, {a.x, b.y, a.z}); + checkPortalPlaneIntersectLineSegment(ref, {a.x, a.y, b.z}); + ref = {a.x, b.y, b.z}; + checkPortalPlaneIntersectLineSegment(ref, {b.x, b.y, b.z}); + checkPortalPlaneIntersectLineSegment(ref, {a.x, a.y, b.z}); + checkPortalPlaneIntersectLineSegment(ref, {a.x, b.y, a.z}); + ref = {b.x, a.y, b.z}; + checkPortalPlaneIntersectLineSegment(ref, {a.x, a.y, b.z}); + checkPortalPlaneIntersectLineSegment(ref, {b.x, b.y, b.z}); + checkPortalPlaneIntersectLineSegment(ref, {b.x, a.y, a.z}); + ref = {b.x, b.y, a.z}; + checkPortalPlaneIntersectLineSegment(ref, {a.x, b.y, a.z}); + checkPortalPlaneIntersectLineSegment(ref, {b.x, a.y, a.z}); + checkPortalPlaneIntersectLineSegment(ref, {b.x, b.y, b.z}); // convert the intersections to a local space AABB (+z is up, +y is left) Vector localMins(666, 666, 666); diff --git a/thirdparty/monocle_implicit_conversions.hpp b/thirdparty/monocle_implicit_conversions.hpp new file mode 100644 index 00000000..fbc9e8ca --- /dev/null +++ b/thirdparty/monocle_implicit_conversions.hpp @@ -0,0 +1,53 @@ +#pragma once + +// include this file before any monocle files to allow implicit conversions between monocle/SDK + +#include "mathlib/vector.h" +#include "mathlib/mathlib.h" +#include "mathlib/vmatrix.h" +#include "mathlib/vplane.h" + +#include + +#define MON_VECTOR_CLASS_EXTRA \ + constexpr Vector(const ::Vector& v) : x(v.x), y(v.y), z(v.z) {} \ + operator const ::Vector&() const \ + { \ + return reinterpret_cast(*this); \ + } + +#define MON_QANGLE_CLASS_EXTRA \ + constexpr QAngle(const ::QAngle& v) : x(v.x), y(v.y), z(v.z) {} \ + operator const ::QAngle&() const \ + { \ + return reinterpret_cast(*this); \ + } + +#define MON_MATRIX3X4_CLASS_EXTRA \ + constexpr matrix3x4_t(const ::matrix3x4_t& m) \ + { \ + *this = std::bit_cast(m); \ + } \ + operator const ::matrix3x4_t&() const \ + { \ + return reinterpret_cast(*this); \ + } + +#define MON_VMATRIX_CLASS_EXTRA \ + constexpr VMatrix(const ::VMatrix& vm) \ + { \ + for (int i = 0; i < 4; ++i) \ + for (int j = 0; j < 4; ++j) \ + m[i][j] = vm.m[i][j]; \ + } \ + operator const ::VMatrix&() const \ + { \ + return reinterpret_cast(*this); \ + } + +#define MON_VPLANE_CLASS_EXTRA \ + constexpr VPlane(const ::VPlane& plane) : n(plane.m_Normal), d(plane.m_Dist) {} \ + operator const ::VPlane&() const \ + { \ + return reinterpret_cast(*this); \ + }