aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack <66967891+ASpoonPlaysGames@users.noreply.github.com>2024-02-05 17:01:22 +0000
committerGitHub <noreply@github.com>2024-02-05 18:01:22 +0100
commit73262ca616f0623a9715ceac90c17b0da4b320d7 (patch)
tree4624e5eec9329afdee0bfb67ccc64e9a935d4484
parentedf013952ca2d110f190dc8cd16e5529846656e4 (diff)
downloadNorthstarLauncher-73262ca616f0623a9715ceac90c17b0da4b320d7.tar.gz
NorthstarLauncher-73262ca616f0623a9715ceac90c17b0da4b320d7.zip
Port navmesh debug renderer from primedev (#626)
Adds support for rendering navmeshes in-game using debug overlay Cherry-picked from primedev, originally written by F1F7Y Co-authored-by: F1F7Y <filip.bartos07@proton.me> Co-authored-by: Maya <11448698+RoyalBlue1@users.noreply.github.com>
-rw-r--r--primedev/Northstar.cmake9
-rw-r--r--primedev/client/cdll_client_int.h5
-rw-r--r--primedev/client/debugoverlay.cpp69
-rw-r--r--primedev/client/debugoverlay.h28
-rw-r--r--primedev/client/entity_client_tools.cpp13
-rw-r--r--primedev/core/math/math_pfns.h7
-rw-r--r--primedev/core/math/vector.h332
-rw-r--r--primedev/core/math/vplane.h106
-rw-r--r--primedev/core/tier1.cpp19
-rw-r--r--primedev/core/tier1.h12
-rw-r--r--primedev/scripts/scriptdatatables.cpp36
-rw-r--r--primedev/server/ai_helper.cpp159
-rw-r--r--primedev/server/ai_helper.h13
-rw-r--r--primedev/server/ai_navmesh.cpp6
-rw-r--r--primedev/server/ai_navmesh.h260
-rw-r--r--primedev/shared/exploit_fixes/exploitfixes.cpp20
-rw-r--r--primedev/toolframework/itoolentity.h46
17 files changed, 1026 insertions, 114 deletions
diff --git a/primedev/Northstar.cmake b/primedev/Northstar.cmake
index 00a8dcaf..6b9c2380 100644
--- a/primedev/Northstar.cmake
+++ b/primedev/Northstar.cmake
@@ -16,6 +16,7 @@ add_library(
"client/debugoverlay.cpp"
"client/demofixes.cpp"
"client/diskvmtfixes.cpp"
+ "client/entity_client_tools.cpp"
"client/languagehooks.cpp"
"client/latencyflex.cpp"
"client/localchatwriter.cpp"
@@ -41,7 +42,9 @@ add_library(
"core/math/bits.h"
"core/math/color.cpp"
"core/math/color.h"
+ "core/math/math_pfns.h"
"core/math/vector.h"
+ "core/math/vplane.h"
"core/hooks.cpp"
"core/hooks.h"
"core/macros.h"
@@ -53,6 +56,8 @@ add_library(
"core/sourceinterface.h"
"core/tier0.cpp"
"core/tier0.h"
+ "core/tier1.cpp"
+ "core/tier1.h"
"dedicated/dedicated.cpp"
"dedicated/dedicated.h"
"dedicated/dedicatedlogtoclient.cpp"
@@ -116,6 +121,10 @@ add_library(
"server/auth/serverauthentication.cpp"
"server/auth/serverauthentication.h"
"server/alltalk.cpp"
+ "server/ai_helper.cpp"
+ "server/ai_helper.h"
+ "server/ai_navmesh.cpp"
+ "server/ai_navmesh.h"
"server/buildainfile.cpp"
"server/r2server.cpp"
"server/r2server.h"
diff --git a/primedev/client/cdll_client_int.h b/primedev/client/cdll_client_int.h
new file mode 100644
index 00000000..a32ccbeb
--- /dev/null
+++ b/primedev/client/cdll_client_int.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "toolframework/itoolentity.h"
+
+inline IClientTools* g_pClientTools = nullptr;
diff --git a/primedev/client/debugoverlay.cpp b/primedev/client/debugoverlay.cpp
index 8e860218..a67b8355 100644
--- a/primedev/client/debugoverlay.cpp
+++ b/primedev/client/debugoverlay.cpp
@@ -1,6 +1,9 @@
+#include "debugoverlay.h"
+
#include "dedicated/dedicated.h"
#include "core/convar/cvar.h"
#include "core/math/vector.h"
+#include "server/ai_helper.h"
AUTOHOOK_INIT()
@@ -122,48 +125,13 @@ struct OverlaySphere_t : public OverlayBase_t
bool m_bWireframe;
};
-typedef bool (*OverlayBase_t__IsDeadType)(OverlayBase_t* a1);
-static OverlayBase_t__IsDeadType OverlayBase_t__IsDead;
-typedef void (*OverlayBase_t__DestroyOverlayType)(OverlayBase_t* a1);
-static OverlayBase_t__DestroyOverlayType OverlayBase_t__DestroyOverlay;
+static bool (*OverlayBase_t__IsDead)(OverlayBase_t* a1);
+static void (*OverlayBase_t__DestroyOverlay)(OverlayBase_t* a1);
static ConVar* Cvar_enable_debug_overlays;
LPCRITICAL_SECTION s_OverlayMutex;
-// Render Line
-typedef void (*RenderLineType)(const Vector3& v1, const Vector3& v2, Color c, bool bZBuffer);
-static RenderLineType RenderLine;
-
-// Render box
-typedef void (*RenderBoxType)(
- const Vector3& vOrigin, const QAngle& angles, const Vector3& vMins, const Vector3& vMaxs, Color c, bool bZBuffer, bool bInsideOut);
-static RenderBoxType RenderBox;
-
-// Render wireframe box
-static RenderBoxType RenderWireframeBox;
-
-// Render swept box
-typedef void (*RenderWireframeSweptBoxType)(
- const Vector3& vStart, const Vector3& vEnd, const QAngle& angles, const Vector3& vMins, const Vector3& vMaxs, Color c, bool bZBuffer);
-RenderWireframeSweptBoxType RenderWireframeSweptBox;
-
-// Render Triangle
-typedef void (*RenderTriangleType)(const Vector3& p1, const Vector3& p2, const Vector3& p3, Color c, bool bZBuffer);
-static RenderTriangleType RenderTriangle;
-
-// Render Axis
-typedef void (*RenderAxisType)(const Vector3& vOrigin, float flScale, bool bZBuffer);
-static RenderAxisType RenderAxis;
-
-// I dont know
-typedef void (*RenderUnknownType)(const Vector3& vUnk, float flUnk, bool bUnk);
-static RenderUnknownType RenderUnknown;
-
-// Render Sphere
-typedef void (*RenderSphereType)(const Vector3& vCenter, float flRadius, int nTheta, int nPhi, Color c, bool bZBuffer);
-static RenderSphereType RenderSphere;
-
OverlayBase_t** s_pOverlays;
int* g_nRenderTickCount;
@@ -317,6 +285,11 @@ void, __fastcall, (bool bRender))
}
}
+ if (bRender && Cvar_enable_debug_overlays->GetBool())
+ {
+ g_pAIHelper->DrawNavmeshPolys();
+ }
+
LeaveCriticalSection(s_OverlayMutex);
}
@@ -324,17 +297,17 @@ ON_DLL_LOAD_CLIENT_RELIESON("engine.dll", DebugOverlay, ConVar, (CModule module)
{
AUTOHOOK_DISPATCH()
- OverlayBase_t__IsDead = module.Offset(0xACAC0).RCast<OverlayBase_t__IsDeadType>();
- OverlayBase_t__DestroyOverlay = module.Offset(0xAB680).RCast<OverlayBase_t__DestroyOverlayType>();
-
- RenderLine = module.Offset(0x192A70).RCast<RenderLineType>();
- RenderBox = module.Offset(0x192520).RCast<RenderBoxType>();
- RenderWireframeBox = module.Offset(0x193DA0).RCast<RenderBoxType>();
- RenderWireframeSweptBox = module.Offset(0x1945A0).RCast<RenderWireframeSweptBoxType>();
- RenderTriangle = module.Offset(0x193940).RCast<RenderTriangleType>();
- RenderAxis = module.Offset(0x1924D0).RCast<RenderAxisType>();
- RenderSphere = module.Offset(0x194170).RCast<RenderSphereType>();
- RenderUnknown = module.Offset(0x1924E0).RCast<RenderUnknownType>();
+ OverlayBase_t__IsDead = module.Offset(0xACAC0).RCast<decltype(OverlayBase_t__IsDead)>();
+ OverlayBase_t__DestroyOverlay = module.Offset(0xAB680).RCast<decltype(OverlayBase_t__DestroyOverlay)>();
+
+ RenderLine = module.Offset(0x192A70).RCast<decltype(RenderLine)>();
+ RenderBox = module.Offset(0x192520).RCast<decltype(RenderBox)>();
+ RenderWireframeBox = module.Offset(0x193DA0).RCast<decltype(RenderWireframeBox)>();
+ RenderWireframeSweptBox = module.Offset(0x1945A0).RCast<decltype(RenderWireframeSweptBox)>();
+ RenderTriangle = module.Offset(0x193940).RCast<decltype(RenderTriangle)>();
+ RenderAxis = module.Offset(0x1924D0).RCast<decltype(RenderAxis)>();
+ RenderSphere = module.Offset(0x194170).RCast<decltype(RenderSphere)>();
+ RenderUnknown = module.Offset(0x1924E0).RCast<decltype(RenderUnknown)>();
s_OverlayMutex = module.Offset(0x10DB0A38).RCast<LPCRITICAL_SECTION>();
diff --git a/primedev/client/debugoverlay.h b/primedev/client/debugoverlay.h
new file mode 100644
index 00000000..498bfafd
--- /dev/null
+++ b/primedev/client/debugoverlay.h
@@ -0,0 +1,28 @@
+#pragma once
+
+// Render Line
+inline void (*RenderLine)(const Vector3& v1, const Vector3& v2, Color c, bool bZBuffer);
+
+// Render box
+inline void (*RenderBox)(
+ const Vector3& vOrigin, const QAngle& angles, const Vector3& vMins, const Vector3& vMaxs, Color c, bool bZBuffer, bool bInsideOut);
+
+// Render wireframe box
+inline void (*RenderWireframeBox)(
+ const Vector3& vOrigin, const QAngle& angles, const Vector3& vMins, const Vector3& vMaxs, Color c, bool bZBuffer, bool bInsideOut);
+
+// Render swept box
+inline void (*RenderWireframeSweptBox)(
+ const Vector3& vStart, const Vector3& vEnd, const QAngle& angles, const Vector3& vMins, const Vector3& vMaxs, Color c, bool bZBuffer);
+
+// Render Triangle
+inline void (*RenderTriangle)(const Vector3& p1, const Vector3& p2, const Vector3& p3, Color c, bool bZBuffer);
+
+// Render Axis
+inline void (*RenderAxis)(const Vector3& vOrigin, float flScale, bool bZBuffer);
+
+// I dont know
+inline void (*RenderUnknown)(const Vector3& vUnk, float flUnk, bool bUnk);
+
+// Render Sphere
+inline void (*RenderSphere)(const Vector3& vCenter, float flRadius, int nTheta, int nPhi, Color c, bool bZBuffer);
diff --git a/primedev/client/entity_client_tools.cpp b/primedev/client/entity_client_tools.cpp
new file mode 100644
index 00000000..d6f0be11
--- /dev/null
+++ b/primedev/client/entity_client_tools.cpp
@@ -0,0 +1,13 @@
+#include "toolframework/itoolentity.h"
+#include "client/cdll_client_int.h"
+#include "core/tier1.h"
+
+class CClientTools : public IClientTools
+{
+public:
+};
+
+ON_DLL_LOAD("client.dll", ClientClientTools, (CModule module))
+{
+ g_pClientTools = Sys_GetFactoryPtr("client.dll", "VCLIENTTOOLS001").RCast<IClientTools*>();
+}
diff --git a/primedev/core/math/math_pfns.h b/primedev/core/math/math_pfns.h
new file mode 100644
index 00000000..4dca9806
--- /dev/null
+++ b/primedev/core/math/math_pfns.h
@@ -0,0 +1,7 @@
+#pragma once
+
+inline float FastSqrt(float x)
+{
+ __m128 root = _mm_sqrt_ss(_mm_load_ss(&x));
+ return *(reinterpret_cast<float*>(&root));
+}
diff --git a/primedev/core/math/vector.h b/primedev/core/math/vector.h
index 8684908f..e62f2c93 100644
--- a/primedev/core/math/vector.h
+++ b/primedev/core/math/vector.h
@@ -1,47 +1,331 @@
+#pragma once
+
+#include "bits.h"
+#include "math_pfns.h"
+
#include <cmath>
-#pragma once
+#define DEG2RAD(a) (a) * (3.14159265358979323846f / 180.0f)
+#define RAD2DEG(a) (a) * (180.0f / 3.14159265358979323846f)
-union Vector3
+class Vector3
{
- struct
+public:
+ float x, y, z;
+
+ Vector3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
+ Vector3(float _f) : x(_f), y(_f), z(_f) {}
+ Vector3() : x(0.0f), y(0.0f), z(0.0f) {}
+
+ inline bool IsValid()
{
- float x;
- float y;
- float z;
- };
+ return IsFinite(x) && IsFinite(y) && IsFinite(z);
+ }
- float raw[3];
+ inline void Init(float fX = 0.0f, float fY = 0.0f, float fZ = 0.0f)
+ {
+ x = fX;
+ y = fY;
+ z = fZ;
+ }
- void MakeValid()
+ inline float Length()
{
- for (auto& fl : raw)
- if (std::isnan(fl))
- fl = 0;
+ return FastSqrt(x * x + y * y + z * z);
}
- // todo: more operators maybe
- bool operator==(const Vector3& other)
+ inline float DistTo(const Vector3& vOther)
{
- return x == other.x && y == other.y && z == other.z;
+ Vector3 vDelta;
+ vDelta.x = vOther.x - x;
+ vDelta.y = vOther.y - y;
+ vDelta.z = vOther.z - z;
+
+ return vDelta.Length();
+ }
+
+ float Dot(const Vector3& vOther) const
+ {
+ return x * vOther.x + y * vOther.y + z * vOther.z;
}
+
+ // Cross product between two vectors.
+ Vector3 Cross(const Vector3& vOther) const;
+
+ void Normalize();
+
+ bool operator==(const Vector3& v) const;
+ bool operator!=(const Vector3& v) const;
+
+ FORCEINLINE Vector3& operator+=(const Vector3& v);
+ FORCEINLINE Vector3& operator-=(const Vector3& v);
+ FORCEINLINE Vector3& operator*=(const Vector3& v);
+ FORCEINLINE Vector3& operator*=(float s);
+ FORCEINLINE Vector3& operator/=(const Vector3& v);
+ FORCEINLINE Vector3& operator/=(float s);
+ FORCEINLINE Vector3& operator+=(float fl); ///< broadcast add
+ FORCEINLINE Vector3& operator-=(float fl);
+
+ // arithmetic operations
+ Vector3 operator-(void) const;
+
+ Vector3 operator+(const Vector3& v) const;
+ Vector3 operator-(const Vector3& v) const;
+ Vector3 operator*(const Vector3& v) const;
+ Vector3 operator/(const Vector3& v) const;
+ Vector3 operator*(float fl) const;
+ Vector3 operator/(float fl) const;
};
-union QAngle
+FORCEINLINE void VectorAdd(const Vector3& a, const Vector3& b, Vector3& result);
+FORCEINLINE void VectorSubtract(const Vector3& a, const Vector3& b, Vector3& result);
+FORCEINLINE void VectorMultiply(const Vector3& a, float b, Vector3& result);
+FORCEINLINE void VectorMultiply(const Vector3& a, const Vector3& b, Vector3& result);
+FORCEINLINE void VectorDivide(const Vector3& a, float b, Vector3& result);
+FORCEINLINE void VectorDivide(const Vector3& a, const Vector3& b, Vector3& result);
+
+inline bool Vector3::operator==(const Vector3& src) const
+{
+ return (src.x == x) && (src.y == y) && (src.z == z);
+}
+
+inline bool Vector3::operator!=(const Vector3& src) const
+{
+ return (src.x != x) || (src.y != y) || (src.z != z);
+}
+
+FORCEINLINE Vector3& Vector3::operator+=(const Vector3& v)
+{
+ x += v.x;
+ y += v.y;
+ z += v.z;
+ return *this;
+}
+
+FORCEINLINE Vector3& Vector3::operator-=(const Vector3& v)
+{
+ x -= v.x;
+ y -= v.y;
+ z -= v.z;
+ return *this;
+}
+
+FORCEINLINE Vector3& Vector3::operator*=(float fl)
+{
+ x *= fl;
+ y *= fl;
+ z *= fl;
+ return *this;
+}
+
+FORCEINLINE Vector3& Vector3::operator*=(const Vector3& v)
+{
+ x *= v.x;
+ y *= v.y;
+ z *= v.z;
+ return *this;
+}
+
+// this ought to be an opcode.
+FORCEINLINE Vector3& Vector3::operator+=(float fl)
+{
+ x += fl;
+ y += fl;
+ z += fl;
+ return *this;
+}
+
+FORCEINLINE Vector3& Vector3::operator-=(float fl)
+{
+ x -= fl;
+ y -= fl;
+ z -= fl;
+ return *this;
+}
+
+FORCEINLINE Vector3& Vector3::operator/=(float fl)
+{
+ float oofl = 1.0f / fl;
+ x *= oofl;
+ y *= oofl;
+ z *= oofl;
+ return *this;
+}
+
+FORCEINLINE Vector3& Vector3::operator/=(const Vector3& v)
+{
+ x /= v.x;
+ y /= v.y;
+ z /= v.z;
+ return *this;
+}
+
+inline Vector3 Vector3::operator-(void) const
+{
+ return Vector3(-x, -y, -z);
+}
+
+inline Vector3 Vector3::operator+(const Vector3& v) const
{
- struct
+ Vector3 res;
+ VectorAdd(*this, v, res);
+ return res;
+}
+
+inline Vector3 Vector3::operator-(const Vector3& v) const
+{
+ Vector3 res;
+ VectorSubtract(*this, v, res);
+ return res;
+}
+
+inline Vector3 Vector3::operator*(float fl) const
+{
+ Vector3 res;
+ VectorMultiply(*this, fl, res);
+ return res;
+}
+
+inline Vector3 Vector3::operator*(const Vector3& v) const
+{
+ Vector3 res;
+ VectorMultiply(*this, v, res);
+ return res;
+}
+
+inline Vector3 Vector3::operator/(float fl) const
+{
+ Vector3 res;
+ VectorDivide(*this, fl, res);
+ return res;
+}
+
+inline Vector3 Vector3::operator/(const Vector3& v) const
+{
+ Vector3 res;
+ VectorDivide(*this, v, res);
+ return res;
+}
+
+inline Vector3 operator*(float fl, const Vector3& v)
+{
+ return v * fl;
+}
+
+inline Vector3 Vector3::Cross(const Vector3& vOther) const
+{
+ return Vector3(y * vOther.z - z * vOther.y, z * vOther.x - x * vOther.z, x * vOther.y - y * vOther.x);
+}
+
+inline void Vector3::Normalize()
+{
+ float fLen = Length();
+ x /= fLen;
+ y /= fLen;
+ z /= fLen;
+}
+
+inline Vector3 StringToVector(char* pString)
+{
+ Vector3 vRet;
+
+ int length = 0;
+ while (pString[length])
{
- float x;
- float y;
- float z;
- float w;
- };
+ if ((pString[length] == '<') || (pString[length] == '>'))
+ pString[length] = '\0';
+ length++;
+ }
+
+ int startOfFloat = 1;
+ int currentIndex = 1;
+
+ while (pString[currentIndex] && (pString[currentIndex] != ','))
+ currentIndex++;
+ pString[currentIndex] = '\0';
+ vRet.x = std::stof(&pString[startOfFloat]);
+ startOfFloat = ++currentIndex;
- float raw[4];
+ while (pString[currentIndex] && (pString[currentIndex] != ','))
+ currentIndex++;
+ pString[currentIndex] = '\0';
+ vRet.y = std::stof(&pString[startOfFloat]);
+ startOfFloat = ++currentIndex;
+
+ while (pString[currentIndex] && (pString[currentIndex] != ','))
+ currentIndex++;
+ pString[currentIndex] = '\0';
+ vRet.z = std::stof(&pString[startOfFloat]);
+ startOfFloat = ++currentIndex;
+
+ return vRet;
+}
+
+FORCEINLINE void VectorAdd(const Vector3& a, const Vector3& b, Vector3& c)
+{
+ c.x = a.x + b.x;
+ c.y = a.y + b.y;
+ c.z = a.z + b.z;
+}
+
+FORCEINLINE void VectorSubtract(const Vector3& a, const Vector3& b, Vector3& c)
+{
+ c.x = a.x - b.x;
+ c.y = a.y - b.y;
+ c.z = a.z - b.z;
+}
+
+FORCEINLINE void VectorMultiply(const Vector3& a, float b, Vector3& c)
+{
+ c.x = a.x * b;
+ c.y = a.y * b;
+ c.z = a.z * b;
+}
+
+FORCEINLINE void VectorMultiply(const Vector3& a, const Vector3& b, Vector3& c)
+{
+ c.x = a.x * b.x;
+ c.y = a.y * b.y;
+ c.z = a.z * b.z;
+}
+
+FORCEINLINE void VectorDivide(const Vector3& a, float b, Vector3& c)
+{
+ float oob = 1.0f / b;
+ c.x = a.x * oob;
+ c.y = a.y * oob;
+ c.z = a.z * oob;
+}
+
+FORCEINLINE void VectorDivide(const Vector3& a, const Vector3& b, Vector3& c)
+{
+ c.x = a.x / b.x;
+ c.y = a.y / b.y;
+ c.z = a.z / b.z;
+}
+
+class QAngle
+{
+public:
+ float x;
+ float y;
+ float z;
+
+ QAngle(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
+ QAngle(float _f) : x(_f), y(_f), z(_f) {}
+ QAngle() : x(0.0f), y(0.0f), z(0.0f) {}
+
+ Vector3 GetNormal() const;
// todo: more operators maybe
bool operator==(const QAngle& other)
{
- return x == other.x && y == other.y && z == other.z && w == other.w;
+ return x == other.x && y == other.y && z == other.z;
}
};
+
+inline Vector3 QAngle::GetNormal() const
+{
+ Vector3 ret(cos(DEG2RAD(y)), sin(DEG2RAD(y)), -sin(DEG2RAD(x)));
+ return ret;
+}
diff --git a/primedev/core/math/vplane.h b/primedev/core/math/vplane.h
new file mode 100644
index 00000000..8b8de423
--- /dev/null
+++ b/primedev/core/math/vplane.h
@@ -0,0 +1,106 @@
+#pragma once
+
+typedef int SideType;
+
+// Used to represent sides of things like planes.
+#define SIDE_FRONT 0
+#define SIDE_BACK 1
+#define SIDE_ON 2
+
+#define VP_EPSILON 0.01f
+
+class VPlane
+{
+public:
+ VPlane();
+ VPlane(const Vector3& vNormal, float dist);
+ VPlane(const Vector3& vPoint, const QAngle& ang);
+
+ void Init(const Vector3& vNormal, float dist);
+
+ // Return the distance from the point to the plane.
+ float DistTo(const Vector3& vVec) const;
+
+ // Copy.
+ VPlane& operator=(const VPlane& thePlane);
+
+ // Returns SIDE_ON, SIDE_FRONT, or SIDE_BACK.
+ // The epsilon for SIDE_ON can be passed in.
+ SideType GetPointSide(const Vector3& vPoint, float sideEpsilon = VP_EPSILON) const;
+
+ // Returns SIDE_FRONT or SIDE_BACK.
+ SideType GetPointSideExact(const Vector3& vPoint) const;
+
+ // Get a point on the plane (normal*dist).
+ Vector3 GetPointOnPlane() const;
+
+ // Snap the specified point to the plane (along the plane's normal).
+ Vector3 SnapPointToPlane(const Vector3& vPoint) const;
+
+public:
+ Vector3 m_Normal;
+ float m_Dist;
+};
+
+//-----------------------------------------------------------------------------
+// Inlines.
+//-----------------------------------------------------------------------------
+inline VPlane::VPlane() {}
+
+inline VPlane::VPlane(const Vector3& vNormal, float dist)
+{
+ m_Normal = vNormal;
+ m_Dist = dist;
+}
+
+inline VPlane::VPlane(const Vector3& vPoint, const QAngle& ang)
+{
+ m_Normal = ang.GetNormal();
+ m_Dist = vPoint.x * m_Normal.x + vPoint.y * m_Normal.y + vPoint.z * m_Normal.z;
+}
+
+inline void VPlane::Init(const Vector3& vNormal, float dist)
+{
+ m_Normal = vNormal;
+ m_Dist = dist;
+}
+
+inline float VPlane::DistTo(const Vector3& vVec) const
+{
+ return vVec.Dot(m_Normal) - m_Dist;
+}
+
+inline VPlane& VPlane::operator=(const VPlane& thePlane)
+{
+ m_Normal = thePlane.m_Normal;
+ m_Dist = thePlane.m_Dist;
+ return *this;
+}
+
+inline Vector3 VPlane::GetPointOnPlane() const
+{
+ return m_Normal * m_Dist;
+}
+
+inline Vector3 VPlane::SnapPointToPlane(const Vector3& vPoint) const
+{
+ return vPoint - m_Normal * DistTo(vPoint);
+}
+
+inline SideType VPlane::GetPointSide(const Vector3& vPoint, float sideEpsilon) const
+{
+ float fDist;
+
+ fDist = DistTo(vPoint);
+ if (fDist >= sideEpsilon)
+ return SIDE_FRONT;
+ else if (fDist <= -sideEpsilon)
+ return SIDE_BACK;
+ else
+ return SIDE_ON;
+}
+
+inline SideType VPlane::GetPointSideExact(const Vector3& vPoint) const
+{
+ return DistTo(vPoint) > 0.0f ? SIDE_FRONT : SIDE_BACK;
+}
diff --git a/primedev/core/tier1.cpp b/primedev/core/tier1.cpp
new file mode 100644
index 00000000..a2995496
--- /dev/null
+++ b/primedev/core/tier1.cpp
@@ -0,0 +1,19 @@
+#include "tier1.h"
+
+// Note: this file is tier1/interface.cpp in primedev, but given that tier0 is yet to be split
+// I am following the existing "pattern" and putting this here
+
+CMemoryAddress Sys_GetFactoryPtr(const std::string& svModuleName, const std::string& svFactoryName)
+{
+ HMODULE hModule = GetModuleHandleA(svModuleName.c_str());
+
+ if (!hModule)
+ {
+ spdlog::error("Failed to get module handle of '{}'!", svModuleName.c_str());
+ exit(EXIT_FAILURE);
+ }
+
+ CreateInterfaceFn fnCreateInterface = reinterpret_cast<CreateInterfaceFn>(GetProcAddress(hModule, CREATEINTERFACE_PROCNAME));
+
+ return fnCreateInterface(svFactoryName.c_str(), NULL);
+}
diff --git a/primedev/core/tier1.h b/primedev/core/tier1.h
new file mode 100644
index 00000000..5be58274
--- /dev/null
+++ b/primedev/core/tier1.h
@@ -0,0 +1,12 @@
+#pragma once
+
+// Note: this file is tier1/interface.h in primedev, but given that tier0 is yet to be split
+// I am following the existing "pattern" and putting this here
+
+#include "memory.h"
+
+#define CREATEINTERFACE_PROCNAME "CreateInterface"
+
+typedef void* (*CreateInterfaceFn)(const char* pName, int* pReturnCode);
+
+CMemoryAddress Sys_GetFactoryPtr(const std::string& svModuleName, const std::string& svFact);
diff --git a/primedev/scripts/scriptdatatables.cpp b/primedev/scripts/scriptdatatables.cpp
index 865b6243..47c3a0f1 100644
--- a/primedev/scripts/scriptdatatables.cpp
+++ b/primedev/scripts/scriptdatatables.cpp
@@ -59,42 +59,6 @@ struct CSVData
std::unordered_map<std::string, CSVData> CSVCache;
-Vector3 StringToVector(char* pString)
-{
- Vector3 vRet;
-
- int length = 0;
- while (pString[length])
- {
- if ((pString[length] == '<') || (pString[length] == '>'))
- pString[length] = '\0';
- length++;
- }
-
- int startOfFloat = 1;
- int currentIndex = 1;
-
- while (pString[currentIndex] && (pString[currentIndex] != ','))
- currentIndex++;
- pString[currentIndex] = '\0';
- vRet.x = std::stof(&pString[startOfFloat]);
- startOfFloat = ++currentIndex;
-
- while (pString[currentIndex] && (pString[currentIndex] != ','))
- currentIndex++;
- pString[currentIndex] = '\0';
- vRet.y = std::stof(&pString[startOfFloat]);
- startOfFloat = ++currentIndex;
-
- while (pString[currentIndex] && (pString[currentIndex] != ','))
- currentIndex++;
- pString[currentIndex] = '\0';
- vRet.z = std::stof(&pString[startOfFloat]);
- startOfFloat = ++currentIndex;
-
- return vRet;
-}
-
// var function GetDataTable( asset path )
REPLACE_SQFUNC(GetDataTable, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER))
{
diff --git a/primedev/server/ai_helper.cpp b/primedev/server/ai_helper.cpp
new file mode 100644
index 00000000..ebb56af2
--- /dev/null
+++ b/primedev/server/ai_helper.cpp
@@ -0,0 +1,159 @@
+#include "ai_helper.h"
+
+#include "client/debugoverlay.h"
+#include "client/cdll_client_int.h"
+#include "engine/hoststate.h"
+
+#include "core/math/vplane.h"
+
+#include <fstream>
+
+const int AINET_VERSION_NUMBER = 57;
+const int AINET_SCRIPT_VERSION_NUMBER = 21;
+const int PLACEHOLDER_CRC = 0;
+
+static ConVar* Cvar_navmesh_debug_hull;
+static ConVar* Cvar_navmesh_debug_camera_radius;
+static ConVar* Cvar_navmesh_debug_lossy_optimization;
+
+//-----------------------------------------------------------------------------
+// Purpose: Get navmesh pointer for hull
+// Output : navmesh*, nullptr if out of range
+//-----------------------------------------------------------------------------
+dtNavMesh* GetNavMeshForHull(int nHull)
+{
+ if (nHull < 1 || nHull > 4)
+ return nullptr;
+
+ return g_pNavMesh[nHull - 1];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Packs two vectors into a __m128i
+// Input : &v1 -
+// &v2 -
+// Output :
+//-----------------------------------------------------------------------------
+__m128i PackVerticesSIMD16(const Vector3& v1, const Vector3& v2)
+{
+ short x1, x2, y1, y2, z1, z2;
+ x1 = static_cast<short>(v1.x);
+ x2 = static_cast<short>(v2.x);
+ y1 = static_cast<short>(v1.y);
+ y2 = static_cast<short>(v2.y);
+ z1 = static_cast<short>(v1.z);
+ z2 = static_cast<short>(v2.z);
+
+ __m128i xRes = _mm_set_epi16(x1, x2, y1, y2, z1, z2, 0, 0);
+
+ if (x1 < x2)
+ xRes = _mm_shufflehi_epi16(xRes, _MM_SHUFFLE(2, 3, 1, 0));
+
+ if (y1 < y2)
+ xRes = _mm_shufflehi_epi16(xRes, _MM_SHUFFLE(3, 2, 0, 1));
+
+ if (z1 < z2)
+ xRes = _mm_shufflelo_epi16(xRes, _MM_SHUFFLE(2, 3, 1, 0));
+
+ return xRes;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw navmesh polys using debug overlay
+// Input : *pNavMesh
+//-----------------------------------------------------------------------------
+void CAI_Helper::DrawNavmeshPolys(dtNavMesh* pNavMesh)
+{
+ if (!pNavMesh)
+ pNavMesh = GetNavMeshForHull(Cvar_navmesh_debug_hull->GetInt());
+ if (!pNavMesh)
+ return;
+
+ Vector3 vCamera;
+ QAngle aCamera;
+ float fFov;
+ g_pClientTools->GetLocalPlayerEyePosition(vCamera, aCamera, fFov);
+
+ const VPlane CullPlane(vCamera - aCamera.GetNormal() * 256.0f, aCamera);
+
+ const float fCamRadius = Cvar_navmesh_debug_camera_radius->GetFloat();
+ const bool bOptimize = Cvar_navmesh_debug_lossy_optimization->GetBool();
+
+ // Used for lossy optimization ( z is ignored when checking for duplicates )
+ // [Fifty]: On a release build i gained around 12 fps on a 1050 ti
+ std::unordered_set<int64_t> sOutlines;
+
+ for (int i = 0; i < pNavMesh->m_maxTiles; ++i)
+ {
+ const dtMeshTile* pTile = &pNavMesh->m_tiles[i];
+
+ if (!pTile->header)
+ continue;
+
+ for (int j = 0; j < pTile->header->polyCount; j++)
+ {
+ const dtPoly* pPoly = &pTile->polys[j];
+
+ if (vCamera.DistTo(pPoly->org) > fCamRadius)
+ continue;
+
+ if (CullPlane.GetPointSide(pPoly->org) != SIDE_FRONT)
+ continue;
+
+ const unsigned int ip = (unsigned int)(pPoly - pTile->polys);
+
+ if (pPoly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
+ {
+ const dtOffMeshConnection* pCon = &pTile->offMeshConnections[ip - pTile->header->offMeshBase];
+ RenderLine(pCon->origin, pCon->dest, Color(255, 250, 50, 255), true);
+ }
+ else
+ {
+ const dtPolyDetail* pDetail = &pTile->detailMeshes[ip];
+
+ Vector3 v[3];
+
+ for (int k = 0; k < pDetail->triCount; ++k)
+ {
+ const unsigned char* t = &pTile->detailTris[(pDetail->triBase + k) * 4];
+ for (int l = 0; l < 3; ++l)
+ {
+ if (t[l] < pPoly->vertCount)
+ {
+ float* pfVerts = &pTile->verts[pPoly->verts[t[l]] * 3];
+ v[l] = Vector3(pfVerts[0], pfVerts[1], pfVerts[2]);
+ }
+ else
+ {
+ float* pfVerts = &pTile->detailVerts[(pDetail->vertBase + t[l] - pPoly->vertCount) * 3];
+ v[l] = Vector3(pfVerts[0], pfVerts[1], pfVerts[2]);
+ }
+ }
+
+ RenderTriangle(v[0], v[1], v[2], Color(110, 200, 220, 160), true);
+
+ auto r = sOutlines.insert(_mm_extract_epi64(PackVerticesSIMD16(v[0], v[1]), 1));
+ if (r.second || !bOptimize)
+ RenderLine(v[0], v[1], Color(0, 0, 150), true);
+
+ r = sOutlines.insert(_mm_extract_epi64(PackVerticesSIMD16(v[1], v[2]), 1));
+ if (r.second || !bOptimize)
+ RenderLine(v[1], v[2], Color(0, 0, 150), true);
+
+ r = sOutlines.insert(_mm_extract_epi64(PackVerticesSIMD16(v[2], v[0]), 1));
+ if (r.second || !bOptimize)
+ RenderLine(v[2], v[0], Color(0, 0, 150), true);
+ }
+ }
+ }
+ }
+}
+
+ON_DLL_LOAD("server.dll", ServerAIHelper, (CModule module))
+{
+ Cvar_navmesh_debug_hull = new ConVar("navmesh_debug_hull", "0", FCVAR_RELEASE, "0 = NONE");
+ Cvar_navmesh_debug_camera_radius =
+ new ConVar("navmesh_debug_camera_radius", "1000", FCVAR_RELEASE, "Radius in which to draw navmeshes");
+ Cvar_navmesh_debug_lossy_optimization =
+ new ConVar("navmesh_debug_lossy_optimization", "1", FCVAR_RELEASE, "Whether to enable lossy navmesh debug draw optimizations");
+}
diff --git a/primedev/server/ai_helper.h b/primedev/server/ai_helper.h
new file mode 100644
index 00000000..0b3c3a53
--- /dev/null
+++ b/primedev/server/ai_helper.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "server/ai_navmesh.h"
+
+dtNavMesh* GetNavMeshForHull(int nHull);
+
+class CAI_Helper
+{
+public:
+ void DrawNavmeshPolys(dtNavMesh* pNavMesh = nullptr);
+};
+
+inline CAI_Helper* g_pAIHelper = nullptr;
diff --git a/primedev/server/ai_navmesh.cpp b/primedev/server/ai_navmesh.cpp
new file mode 100644
index 00000000..966726b2
--- /dev/null
+++ b/primedev/server/ai_navmesh.cpp
@@ -0,0 +1,6 @@
+#include "ai_navmesh.h"
+
+ON_DLL_LOAD("server.dll", ServerAiNavMesh, (CModule module))
+{
+ g_pNavMesh = module.Offset(0x105F5D0).RCast<dtNavMesh**>();
+}
diff --git a/primedev/server/ai_navmesh.h b/primedev/server/ai_navmesh.h
new file mode 100644
index 00000000..65529f7a
--- /dev/null
+++ b/primedev/server/ai_navmesh.h
@@ -0,0 +1,260 @@
+#pragma once
+
+// [Fifty]: Taken from https://github.com/ASpoonPlaysGames/r2recast
+
+#include "core/math/vector.h"
+
+struct dtMeshHeader;
+struct dtMeshTile;
+struct dtPoly;
+struct dtBVNode;
+struct dtLink;
+
+typedef unsigned int dtPolyRef;
+
+/// The maximum number of vertices per navigation polygon.
+/// @ingroup detour
+static const int DT_VERTS_PER_POLYGON = 6;
+
+/// Flags representing the type of a navigation mesh polygon.
+enum dtPolyTypes
+{
+ /// The polygon is a standard convex polygon that is part of the surface of the mesh.
+ DT_POLYTYPE_GROUND = 0,
+ /// The polygon is an off-mesh connection consisting of two vertices.
+ DT_POLYTYPE_OFFMESH_CONNECTION = 1,
+};
+
+/// Configuration parameters used to define multi-tile navigation meshes.
+/// The values are used to allocate space during the initialization of a navigation mesh.
+/// @see dtNavMesh::init()
+/// @ingroup detour
+struct dtNavMeshParams
+{
+ float orig[3]; ///< The world space origin of the navigation mesh's tile space. [(x, y, z)]
+ float tileWidth; ///< The width of each tile. (Along the x-axis.)
+ float tileHeight; ///< The height of each tile. (Along the z-axis.)
+ int maxTiles; ///< The maximum number of tiles the navigation mesh can contain. This and maxPolys are used to calculate how many bits
+ ///< are needed to identify tiles and polygons uniquely.
+ int maxPolys; ///< The maximum number of polygons each tile can contain. This and maxTiles are used to calculate how many bits are
+ ///< needed to identify tiles and polygons uniquely.
+ //
+ //// i hate this
+ int disjointPolyGroupCount = 0;
+ int reachabilityTableSize = 0;
+ int reachabilityTableCount = 0;
+};
+
+/// Defines an navigation mesh off-mesh connection within a dtMeshTile object.
+/// An off-mesh connection is a user defined traversable connection made up to two vertices.
+struct dtOffMeshConnection
+{
+ /// The endpoints of the connection.
+ Vector3 origin;
+ Vector3 dest;
+
+ /// The radius of the endpoints. [Limit: >= 0]
+ float rad;
+
+ /// The polygon reference of the connection within the tile.
+ unsigned short poly;
+
+ /// Link flags.
+ /// @note These are not the connection's user defined flags. Those are assigned via the
+ /// connection's dtPoly definition. These are link flags used for internal purposes.
+ unsigned char flags;
+
+ /// End point side.
+ unsigned char side;
+
+ /// The id of the offmesh connection. (User assigned when the navigation mesh is built.)
+ unsigned int userId;
+
+ float unk[3];
+ float another_unk;
+};
+
+/// A navigation mesh based on tiles of convex polygons.
+/// @ingroup detour
+class dtNavMesh
+{
+public:
+ dtMeshTile** m_posLookup; ///< Tile hash lookup.
+ dtMeshTile* m_nextFree; ///< Freelist of tiles.
+ dtMeshTile* m_tiles; ///< List of tiles.
+
+ void* disjointPolyGroup;
+ int** reachabilityTable;
+
+ __int64 unk;
+ dtNavMeshParams m_params; ///< Current initialization params. TODO: do not store this info twice.
+ float m_orig[3]; ///< Origin of the tile (0,0)
+ float m_tileWidth, m_tileHight; ///< Dimensions of each tile.
+ int m_pad;
+ int m_maxTiles; ///< Max number of tiles.
+
+ int m_tileLutSize; ///< Tile hash lookup size (must be pot).
+ int m_tileLutMask; ///< Tile hash lookup mask.
+
+ int m_saltBits; ///< Number of salt bits in the tile ID.
+ int m_tileBits; ///< Number of tile bits in the tile ID.
+ int m_polyBits; ///< Number of poly bits in the tile ID.
+};
+
+/// Defines the location of detail sub-mesh data within a dtMeshTile.
+struct dtPolyDetail
+{
+ unsigned int vertBase; ///< The offset of the vertices in the dtMeshTile::detailVerts array.
+ unsigned int triBase; ///< The offset of the triangles in the dtMeshTile::detailTris array.
+ unsigned char vertCount; ///< The number of vertices in the sub-mesh.
+ unsigned char triCount; ///< The number of triangles in the sub-mesh.
+};
+
+/// Defines a navigation mesh tile.
+/// @ingroup detour
+struct dtMeshTile
+{
+ int salt; ///< Counter describing modifications to the tile.
+ unsigned int linksFreeList; ///< Index to the next free link.
+ dtMeshHeader* header; ///< The tile header.
+ dtPoly* polys; ///< The tile polygons. [Size: dtMeshHeader::polyCount]
+ void* unkPolyThing;
+ float* verts; ///< The tile vertices. [Size: dtMeshHeader::vertCount]
+ dtLink* links; ///< The tile links. [Size: dtMeshHeader::maxLinkCount]
+ dtPolyDetail* detailMeshes; ///< The tile's detail sub-meshes. [Size: dtMeshHeader::detailMeshCount]
+
+ /// The detail mesh's unique vertices. [(x, y, z) * dtMeshHeader::detailVertCount]
+ float* detailVerts;
+
+ /// The detail mesh's triangles. [(vertA, vertB, vertC, triFlags) * dtMeshHeader::detailTriCount].
+ /// See dtDetailTriEdgeFlags and dtGetDetailTriEdgeFlags.
+ unsigned char* detailTris;
+
+ /// The tile bounding volume nodes. [Size: dtMeshHeader::bvNodeCount]
+ /// (Will be null if bounding volumes are disabled.)
+ dtBVNode* bvTree;
+
+ dtOffMeshConnection* offMeshConnections; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount]
+ void* data; ///< The tile data. (Not directly accessed under normal situations.)
+ int dataSize; ///< Size of the tile data.
+ int flags; ///< Tile flags. (See: #dtTileFlags)
+ dtMeshTile* next; ///< The next free tile, or the next tile in the spatial grid.
+ __int64 unk;
+};
+
+/// Provides high level information related to a dtMeshTile object.
+/// @ingroup detour
+struct dtMeshHeader
+{
+ int magic; ///< Tile magic number. (Used to identify the data format.)
+ int version; ///< Tile data format version number.
+ int x; ///< The x-position of the tile within the dtNavMesh tile grid. (x, y, layer)
+ int y; ///< The y-position of the tile within the dtNavMesh tile grid. (x, y, layer)
+ int layer; ///< The layer of the tile within the dtNavMesh tile grid. (x, y, layer)
+ unsigned int userId; ///< The user defined id of the tile.
+ int polyCount; ///< The number of polygons in the tile.
+ int sth_per_poly;
+ int vertCount; ///< The number of vertices in the tile.
+ int maxLinkCount; ///< The number of allocated links.
+
+ int detailMeshCount;
+
+ /// The number of unique vertices in the detail mesh. (In addition to the polygon vertices.)
+ int detailVertCount;
+
+ int detailTriCount; ///< The number of triangles in the detail mesh.
+ int bvNodeCount; ///< The number of bounding volume nodes. (Zero if bounding volumes are disabled.)
+ int offMeshConCount; ///< The number of off-mesh connections.
+ // int unk1;
+ int offMeshBase; ///< The index of the first polygon which is an off-mesh connection.
+
+ float walkableHeight; ///< The height of the agents using the tile.
+ float walkableRadius; ///< The radius of the agents using the tile.
+ float walkableClimb; ///< The maximum climb height of the agents using the tile.
+ float bmin[3]; ///< The minimum bounds of the tile's AABB. [(x, y, z)]
+ float bmax[3]; ///< The maximum bounds of the tile's AABB. [(x, y, z)]
+
+ /// The bounding volume quantization factor.
+ float bvQuantFactor;
+};
+
+/// Defines a polygon within a dtMeshTile object.
+/// @ingroup detour
+struct dtPoly
+{
+ /// Index to first link in linked list. (Or #DT_NULL_LINK if there is no link.)
+ unsigned int firstLink;
+
+ /// The indices of the polygon's vertices.
+ /// The actual vertices are located in dtMeshTile::verts.
+ unsigned short verts[DT_VERTS_PER_POLYGON];
+
+ /// Packed data representing neighbor polygons references and flags for each edge.
+ unsigned short neis[DT_VERTS_PER_POLYGON];
+
+ /// The user defined polygon flags.
+ unsigned short flags;
+
+ /// The number of vertices in the polygon.
+ unsigned char vertCount;
+
+ /// The bit packed area id and polygon type.
+ /// @note Use the structure's set and get methods to acess this value.
+ unsigned char areaAndtype;
+
+ unsigned short disjointSetId;
+ unsigned short unk; // IDK but looks filled
+ Vector3 org; //
+
+ /// Sets the user defined area id. [Limit: < #DT_MAX_AREAS]
+ inline void setArea(unsigned char a)
+ {
+ areaAndtype = (areaAndtype & 0xc0) | (a & 0x3f);
+ }
+
+ /// Sets the polygon type. (See: #dtPolyTypes.)
+ inline void setType(unsigned char t)
+ {
+ areaAndtype = (areaAndtype & 0x3f) | (t << 6);
+ }
+
+ /// Gets the user defined area id.
+ inline unsigned char getArea() const
+ {
+ return areaAndtype & 0x3f;
+ }
+
+ /// Gets the polygon type. (See: #dtPolyTypes)
+ inline unsigned char getType() const
+ {
+ return areaAndtype >> 6;
+ }
+};
+
+/// Defines a link between polygons.
+/// @note This structure is rarely if ever used by the end user.
+/// @see dtMeshTile
+struct dtLink
+{
+ dtPolyRef ref; ///< Neighbour reference. (The neighbor that is linked to.)
+ unsigned int next; ///< Index of the next link.
+ unsigned char edge; ///< Index of the polygon edge that owns this link.
+ unsigned char side; ///< If a boundary link, defines on which side the link is.
+ unsigned char bmin; ///< If a boundary link, defines the minimum sub-edge area.
+ unsigned char bmax; ///< If a boundary link, defines the maximum sub-edge area.
+ unsigned char jumpType;
+ unsigned char otherUnk;
+ unsigned short reverseLinkIndex;
+};
+
+/// Bounding volume node.
+/// @note This structure is rarely if ever used by the end user.
+/// @see dtMeshTile
+struct dtBVNode
+{
+ unsigned short bmin[3]; ///< Minimum bounds of the node's AABB. [(x, y, z)]
+ unsigned short bmax[3]; ///< Maximum bounds of the node's AABB. [(x, y, z)]
+ int i; ///< The node's index. (Negative for escape sequence.)
+};
+
+inline dtNavMesh** g_pNavMesh = nullptr;
diff --git a/primedev/shared/exploit_fixes/exploitfixes.cpp b/primedev/shared/exploit_fixes/exploitfixes.cpp
index 44651b3c..cade4084 100644
--- a/primedev/shared/exploit_fixes/exploitfixes.cpp
+++ b/primedev/shared/exploit_fixes/exploitfixes.cpp
@@ -222,16 +222,24 @@ void, __fastcall, (void* buf, void* pCmd_move, void* pCmd_from)) // 4C 89 44 24
"ReadUsercmd (command_number delta: " + std::to_string(cmd->command_number - fromCmd->command_number) + "): ";
// fix invalid player angles
- cmd->worldViewAngles.MakeValid();
- cmd->attackangles.MakeValid();
- cmd->localViewAngles.MakeValid();
+ if (!cmd->worldViewAngles.IsValid())
+ cmd->worldViewAngles.Init();
+
+ if (!cmd->attackangles.IsValid())
+ cmd->attackangles.Init();
+
+ if (!cmd->localViewAngles.IsValid())
+ cmd->localViewAngles.Init();
// Fix invalid camera angles
- cmd->cameraPos.MakeValid();
- cmd->cameraAngles.MakeValid();
+ if (!cmd->cameraPos.IsValid())
+ cmd->cameraPos.Init();
+ if (!cmd->cameraAngles.IsValid())
+ cmd->cameraAngles.Init();
// Fix invaid movement vector
- cmd->move.MakeValid();
+ if (!cmd->move.IsValid())
+ cmd->move.Init();
if (cmd->frameTime <= 0 || cmd->tick_count == 0 || cmd->command_time <= 0)
{
diff --git a/primedev/toolframework/itoolentity.h b/primedev/toolframework/itoolentity.h
new file mode 100644
index 00000000..332004f2
--- /dev/null
+++ b/primedev/toolframework/itoolentity.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "core/math/vector.h"
+
+class IClientTools // : public IBaseInterface
+{
+public:
+ virtual void sub_1805E4960() = 0;
+ virtual void sub_1805E4B10() = 0;
+ virtual void sub_1805E4C50() = 0;
+ virtual void sub_1805E5670() = 0;
+ virtual void sub_1805E66C0() = 0;
+ virtual void sub_1805E5910() = 0;
+ virtual void sub_1805E59A0() = 0;
+ virtual void sub_1805E6B10() = 0;
+ virtual void sub_1805E8580() = 0;
+ virtual void sub_1805E59D0() = 0;
+ virtual void sub_1805E57B0() = 0;
+ virtual void sub_1805E5860() = 0;
+ virtual void sub_1805E55A0() = 0;
+ virtual void sub_1805E49C0() = 0;
+ virtual void sub_1805E7580() = 0;
+ virtual void sub_1805E86A0() = 0;
+ virtual void sub_1805E69B0() = 0;
+ virtual void sub_1805E4D70() = 0; // IClientTools::DrawSprite
+ virtual void* GetLocalPlayer() = 0; // return type unknown probably CBasePlayer*
+ virtual bool GetLocalPlayerEyePosition(Vector3& org, QAngle& ang, float& fov) = 0;
+ virtual void sub_1805E5960() = 0;
+ virtual void sub_1805E5650() = 0;
+ virtual void sub_1805E5920() = 0;
+ virtual void sub_1805E64E0() = 0;
+ virtual void sub_1805E63C0() = 0;
+ virtual void sub_1805E64C0() = 0;
+ virtual void sub_1805E6520() = 0;
+ virtual void sub_1805E6770() = 0;
+ virtual void sub_1805E67B0() = 0;
+ virtual void sub_1805E67F0() = 0;
+ virtual void sub_1805E66A0() = 0;
+ virtual void sub_1805E6500() = 0;
+ virtual void sub_1805E63B0() = 0;
+ virtual void sub_1805E54C0() = 0;
+ virtual void sub_1805E53E0() = 0;
+ virtual void sub_1805E6D70() = 0;
+ virtual void sub_1805E50D0() = 0;
+ virtual void sub_1805E65C0() = 0;
+};