fix conflicts
This commit is contained in:
commit
5cb3d3c523
|
@ -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"
|
||||
|
@ -35,7 +36,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"
|
||||
|
@ -47,6 +50,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"
|
||||
|
@ -78,11 +83,16 @@ add_library(
|
|||
"mods/modmanager.h"
|
||||
"mods/modsavefiles.cpp"
|
||||
"mods/modsavefiles.h"
|
||||
"plugins/plugin_abi.h"
|
||||
"plugins/pluginbackend.cpp"
|
||||
"plugins/pluginbackend.h"
|
||||
"plugins/interfaces/interface.h"
|
||||
"plugins/interfaces/interface.cpp"
|
||||
"plugins/interfaces/sys/ISys.h"
|
||||
"plugins/interfaces/sys/ISys.cpp"
|
||||
"plugins/interfaces/IPluginId.h"
|
||||
"plugins/interfaces/IPluginCallbacks.h"
|
||||
"plugins/plugins.cpp"
|
||||
"plugins/plugins.h"
|
||||
"plugins/pluginmanager.h"
|
||||
"plugins/pluginmanager.cpp"
|
||||
"scripts/client/clientchathooks.cpp"
|
||||
"scripts/client/cursorposition.cpp"
|
||||
"scripts/client/scriptbrowserhooks.cpp"
|
||||
|
@ -105,6 +115,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"
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "toolframework/itoolentity.h"
|
||||
|
||||
inline IClientTools* g_pClientTools = nullptr;
|
|
@ -1,6 +1,9 @@
|
|||
#include "debugoverlay.h"
|
||||
|
||||
#include "dedicated/dedicated.h"
|
||||
#include "tier1/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>();
|
||||
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<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>();
|
||||
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>();
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -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*>();
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
#include "dedicated/dedicated.h"
|
||||
#include "plugins/pluginbackend.h"
|
||||
#include "plugins/pluginmanager.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <wchar.h>
|
||||
|
@ -417,7 +417,7 @@ HMODULE, WINAPI, (LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags))
|
|||
if (moduleAddress)
|
||||
{
|
||||
CallLoadLibraryACallbacks(lpLibFileName, moduleAddress);
|
||||
InformPluginsDLLLoad(fs::path(lpLibFileName), moduleAddress);
|
||||
g_pPluginManager->InformDllLoad(moduleAddress, fs::path(lpLibFileName));
|
||||
}
|
||||
|
||||
return moduleAddress;
|
||||
|
@ -459,7 +459,7 @@ HMODULE, WINAPI, (LPCWSTR lpLibFileName))
|
|||
if (moduleAddress)
|
||||
{
|
||||
CallLoadLibraryWCallbacks(lpLibFileName, moduleAddress);
|
||||
InformPluginsDLLLoad(fs::path(lpLibFileName), moduleAddress);
|
||||
g_pPluginManager->InformDllLoad(moduleAddress, fs::path(lpLibFileName));
|
||||
}
|
||||
|
||||
return moduleAddress;
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -1,47 +1,331 @@
|
|||
#include <cmath>
|
||||
|
||||
#pragma once
|
||||
|
||||
union Vector3
|
||||
#include "bits.h"
|
||||
#include "math_pfns.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#define DEG2RAD(a) (a) * (3.14159265358979323846f / 180.0f)
|
||||
#define RAD2DEG(a) (a) * (180.0f / 3.14159265358979323846f)
|
||||
|
||||
class Vector3
|
||||
{
|
||||
struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
public:
|
||||
float x, y, z;
|
||||
|
||||
float raw[3];
|
||||
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) {}
|
||||
|
||||
void MakeValid()
|
||||
inline bool IsValid()
|
||||
{
|
||||
for (auto& fl : raw)
|
||||
if (std::isnan(fl))
|
||||
fl = 0;
|
||||
return IsFinite(x) && IsFinite(y) && IsFinite(z);
|
||||
}
|
||||
|
||||
inline void Init(float fX = 0.0f, float fY = 0.0f, float fZ = 0.0f)
|
||||
{
|
||||
x = fX;
|
||||
y = fY;
|
||||
z = fZ;
|
||||
}
|
||||
|
||||
inline float Length()
|
||||
{
|
||||
return FastSqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
inline float DistTo(const Vector3& vOther)
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
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])
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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 Vector3& other)
|
||||
bool operator==(const QAngle& other)
|
||||
{
|
||||
return x == other.x && y == other.y && z == other.z;
|
||||
}
|
||||
};
|
||||
|
||||
union QAngle
|
||||
inline Vector3 QAngle::GetNormal() const
|
||||
{
|
||||
struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
};
|
||||
|
||||
float raw[4];
|
||||
|
||||
// todo: more operators maybe
|
||||
bool operator==(const QAngle& other)
|
||||
{
|
||||
return x == other.x && y == other.y && z == other.z && w == other.w;
|
||||
}
|
||||
};
|
||||
Vector3 ret(cos(DEG2RAD(y)), sin(DEG2RAD(y)), -sin(DEG2RAD(x)));
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -1,6 +1,13 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
// interface return status
|
||||
enum class InterfaceStatus : int
|
||||
{
|
||||
IFACE_OK = 0,
|
||||
IFACE_FAILED,
|
||||
};
|
||||
|
||||
// literally just copied from ttf2sdk definition
|
||||
typedef void* (*CreateInterfaceFn)(const char* pName, int* pReturnCode);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
|
@ -3,10 +3,10 @@
|
|||
#include "core/memalloc.h"
|
||||
#include "core/vanilla.h"
|
||||
#include "config/profile.h"
|
||||
#include "plugins/plugin_abi.h"
|
||||
#include "plugins/plugins.h"
|
||||
#include "plugins/pluginbackend.h"
|
||||
#include "plugins/pluginmanager.h"
|
||||
#include "util/version.h"
|
||||
#include "util/wininfo.h"
|
||||
#include "squirrel/squirrel.h"
|
||||
#include "server/serverpresence.h"
|
||||
|
||||
|
@ -23,6 +23,8 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
|
|||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
g_NorthstarModule = hModule;
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
|
@ -65,7 +67,6 @@ bool InitialiseNorthstar()
|
|||
g_pServerPresence = new ServerPresenceManager();
|
||||
|
||||
g_pPluginManager = new PluginManager();
|
||||
g_pPluginCommunicationhandler = new PluginCommunicationHandler();
|
||||
g_pPluginManager->LoadPlugins();
|
||||
|
||||
InitialiseSquirrelManagers();
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
#include "engine/r2engine.h"
|
||||
#include "shared/exploit_fixes/ns_limits.h"
|
||||
#include "squirrel/squirrel.h"
|
||||
#include "plugins/plugins.h"
|
||||
#include "plugins/pluginbackend.h"
|
||||
#include "plugins/pluginmanager.h"
|
||||
|
||||
AUTOHOOK_INIT()
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "util/version.h"
|
||||
#include "mods/modmanager.h"
|
||||
#include "plugins/plugins.h"
|
||||
#include "plugins/pluginmanager.h"
|
||||
|
||||
#include <minidumpapiset.h>
|
||||
|
||||
|
@ -524,9 +525,9 @@ void CCrashHandler::FormatLoadedPlugins()
|
|||
if (g_pPluginManager)
|
||||
{
|
||||
spdlog::error("Loaded Plugins:");
|
||||
for (const Plugin& plugin : g_pPluginManager->m_vLoadedPlugins)
|
||||
for (const Plugin& plugin : g_pPluginManager->GetLoadedPlugins())
|
||||
{
|
||||
spdlog::error("\t{}", plugin.name);
|
||||
spdlog::error("\t{}", plugin.GetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ private:
|
|||
const char* VERIFICATION_FLAG = "-disablemodverification";
|
||||
const char* CUSTOM_MODS_URL_FLAG = "-customverifiedurl=";
|
||||
const char* STORE_URL = "https://gcdn.thunderstore.io/live/repository/packages/";
|
||||
const char* DEFAULT_MODS_LIST_URL = "https://raw.githubusercontent.com/R2Northstar/VerifiedMods/master/verified-mods.json";
|
||||
const char* DEFAULT_MODS_LIST_URL = "https://raw.githubusercontent.com/R2Northstar/VerifiedMods/main/verified-mods.json";
|
||||
char* modsListUrl;
|
||||
|
||||
struct VerifiedModVersion
|
||||
|
@ -79,7 +79,7 @@ public:
|
|||
* The Northstar auto-downloading feature does NOT allow automatically installing
|
||||
* all mods for various (notably security) reasons; mods that are candidate to
|
||||
* auto-downloading are rather listed on a GitHub repository
|
||||
* (https://raw.githubusercontent.com/R2Northstar/VerifiedMods/master/verified-mods.json),
|
||||
* (https://raw.githubusercontent.com/R2Northstar/VerifiedMods/main/verified-mods.json),
|
||||
* which this method gets via a HTTP call to load into local state.
|
||||
*
|
||||
* If list fetching fails, local mods list will be initialized as empty, thus
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef IPLUGIN_CALLBACKS_H
|
||||
#define IPLUGIN_CALLBACKS_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdint.h>
|
||||
#include "squirrel/squirrel.h"
|
||||
|
||||
// can't use bitwise ops on enum classes but I don't want these in the global namespace (user defined operators suck)
|
||||
namespace PluginContext
|
||||
{
|
||||
enum : uint64_t
|
||||
{
|
||||
DEDICATED = 0x1,
|
||||
CLIENT = 0x2,
|
||||
};
|
||||
}
|
||||
|
||||
struct PluginNorthstarData
|
||||
{
|
||||
HMODULE pluginHandle;
|
||||
};
|
||||
|
||||
class IPluginCallbacks
|
||||
{
|
||||
public:
|
||||
virtual void
|
||||
Init(HMODULE northstarModule, const PluginNorthstarData* initData, bool reloaded) = 0; // runs after the plugin is loaded and validated
|
||||
virtual void Finalize() = 0; // runs after all plugins have been loaded
|
||||
virtual bool Unload() = 0; // runs just before the library is freed
|
||||
virtual void OnSqvmCreated(CSquirrelVM* sqvm) = 0;
|
||||
virtual void OnSqvmDestroying(CSquirrelVM* sqvm) = 0;
|
||||
virtual void OnLibraryLoaded(HMODULE module, const char* name) = 0;
|
||||
virtual void RunFrame() = 0;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef IPLUGIN_ID_H
|
||||
#define IPLUGIN_ID_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "squirrel/squirrelclasstypes.h"
|
||||
|
||||
#define PLUGIN_ID_VERSION "PluginId001"
|
||||
|
||||
// an identifier for the type of string data requested from the plugin
|
||||
enum class PluginString : int
|
||||
{
|
||||
NAME = 0,
|
||||
LOG_NAME = 1,
|
||||
DEPENDENCY_NAME = 2,
|
||||
};
|
||||
|
||||
// an identifier for the type of bitflag requested from the plugin
|
||||
enum class PluginField : int
|
||||
{
|
||||
CONTEXT = 0,
|
||||
};
|
||||
|
||||
// an interface that is required from every plugin to query data about it
|
||||
class IPluginId
|
||||
{
|
||||
public:
|
||||
virtual const char* GetString(PluginString prop) = 0;
|
||||
virtual int64_t GetField(PluginField prop) = 0;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
#include <string.h>
|
||||
#include "interface.h"
|
||||
|
||||
InterfaceReg* s_pInterfaceRegs;
|
||||
|
||||
InterfaceReg::InterfaceReg(InstantiateInterfaceFn fn, const char* pName) : m_pName(pName)
|
||||
{
|
||||
m_CreateFn = fn;
|
||||
m_pNext = s_pInterfaceRegs;
|
||||
s_pInterfaceRegs = this;
|
||||
}
|
||||
|
||||
void* CreateInterface(const char* pName, InterfaceStatus* pReturnCode)
|
||||
{
|
||||
for (InterfaceReg* pCur = s_pInterfaceRegs; pCur; pCur = pCur->m_pNext)
|
||||
{
|
||||
if (strcmp(pCur->m_pName, pName) == 0)
|
||||
{
|
||||
if (pReturnCode)
|
||||
{
|
||||
*pReturnCode = InterfaceStatus::IFACE_OK;
|
||||
}
|
||||
|
||||
NS::log::PLUGINSYS->info("creating interface {}", pName);
|
||||
return pCur->m_CreateFn();
|
||||
}
|
||||
}
|
||||
|
||||
if (pReturnCode)
|
||||
{
|
||||
*pReturnCode = InterfaceStatus::IFACE_FAILED;
|
||||
}
|
||||
|
||||
NS::log::PLUGINSYS->error("could not find interface {}", pName);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef INTERFACE_H
|
||||
#define INTERFACE_H
|
||||
|
||||
typedef void* (*InstantiateInterfaceFn)();
|
||||
|
||||
// Used internally to register classes.
|
||||
class InterfaceReg
|
||||
{
|
||||
public:
|
||||
InterfaceReg(InstantiateInterfaceFn fn, const char* pName);
|
||||
|
||||
InstantiateInterfaceFn m_CreateFn;
|
||||
const char* m_pName;
|
||||
InterfaceReg* m_pNext;
|
||||
};
|
||||
|
||||
// Use this to expose an interface that can have multiple instances.
|
||||
#define EXPOSE_INTERFACE(className, interfaceName, versionName) \
|
||||
static void* __Create##className##_interface() \
|
||||
{ \
|
||||
return static_cast<interfaceName*>(new className); \
|
||||
} \
|
||||
static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName);
|
||||
|
||||
#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \
|
||||
static void* __Create##className##interfaceName##_interface() \
|
||||
{ \
|
||||
return static_cast<interfaceName*>(&globalVarName); \
|
||||
} \
|
||||
static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName);
|
||||
|
||||
// Use this to expose a singleton interface. This creates the global variable for you automatically.
|
||||
#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \
|
||||
static className __g_##className##_singleton; \
|
||||
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton)
|
||||
|
||||
EXPORT void* CreateInterface(const char* pName, InterfaceStatus* pReturnCode);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,66 @@
|
|||
#include "plugins/interfaces/interface.h"
|
||||
#include "ISys.h"
|
||||
#include "plugins/plugins.h"
|
||||
#include "plugins/pluginmanager.h"
|
||||
|
||||
class CSys : public ISys
|
||||
{
|
||||
public:
|
||||
void Log(HMODULE handle, LogLevel level, char* msg)
|
||||
{
|
||||
spdlog::level::level_enum spdLevel;
|
||||
|
||||
switch (level)
|
||||
{
|
||||
case LogLevel::WARN:
|
||||
spdLevel = spdlog::level::level_enum::warn;
|
||||
break;
|
||||
case LogLevel::ERR:
|
||||
spdLevel = spdlog::level::level_enum::err;
|
||||
break;
|
||||
default:
|
||||
NS::log::PLUGINSYS->warn("Attempted to log with invalid level {}. Defaulting to info", (int)level);
|
||||
case LogLevel::INFO:
|
||||
spdLevel = spdlog::level::level_enum::info;
|
||||
break;
|
||||
}
|
||||
|
||||
std::optional<Plugin> plugin = g_pPluginManager->GetPlugin(handle);
|
||||
if (plugin)
|
||||
{
|
||||
plugin->Log(spdLevel, msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS::log::PLUGINSYS->warn("Attempted to log message '{}' with invalid plugin handle {}", msg, static_cast<void*>(handle));
|
||||
}
|
||||
}
|
||||
|
||||
void Unload(HMODULE handle)
|
||||
{
|
||||
std::optional<Plugin> plugin = g_pPluginManager->GetPlugin(handle);
|
||||
if (plugin)
|
||||
{
|
||||
plugin->Unload();
|
||||
}
|
||||
else
|
||||
{
|
||||
NS::log::PLUGINSYS->warn("Attempted to unload plugin with invalid handle {}", static_cast<void*>(handle));
|
||||
}
|
||||
}
|
||||
|
||||
void Reload(HMODULE handle)
|
||||
{
|
||||
std::optional<Plugin> plugin = g_pPluginManager->GetPlugin(handle);
|
||||
if (plugin)
|
||||
{
|
||||
plugin->Reload();
|
||||
}
|
||||
else
|
||||
{
|
||||
NS::log::PLUGINSYS->warn("Attempted to reload plugin with invalid handle {}", static_cast<void*>(handle));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EXPOSE_SINGLE_INTERFACE(CSys, ISys, SYS_VERSION);
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef ILOGGING_H
|
||||
#define ILOGGING_H
|
||||
|
||||
#define SYS_VERSION "NSSys001"
|
||||
|
||||
enum class LogLevel : int
|
||||
{
|
||||
INFO = 0,
|
||||
WARN,
|
||||
ERR,
|
||||
};
|
||||
|
||||
class ISys
|
||||
{
|
||||
public:
|
||||
virtual void Log(HMODULE handle, LogLevel level, char* msg) = 0;
|
||||
virtual void Unload(HMODULE handle) = 0;
|
||||
virtual void Reload(HMODULE handle) = 0;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,151 +0,0 @@
|
|||
#pragma once
|
||||
#include "squirrel/squirrelclasstypes.h"
|
||||
|
||||
#define ABI_VERSION 3
|
||||
|
||||
enum PluginLoadDLL
|
||||
{
|
||||
ENGINE = 0,
|
||||
CLIENT,
|
||||
SERVER
|
||||
};
|
||||
|
||||
enum ObjectType
|
||||
{
|
||||
CONCOMMANDS = 0,
|
||||
CONVAR = 1,
|
||||
};
|
||||
|
||||
struct SquirrelFunctions
|
||||
{
|
||||
RegisterSquirrelFuncType RegisterSquirrelFunc;
|
||||
sq_defconstType __sq_defconst;
|
||||
|
||||
sq_compilebufferType __sq_compilebuffer;
|
||||
sq_callType __sq_call;
|
||||
sq_raiseerrorType __sq_raiseerror;
|
||||
sq_compilefileType __sq_compilefile;
|
||||
|
||||
sq_newarrayType __sq_newarray;
|
||||
sq_arrayappendType __sq_arrayappend;
|
||||
|
||||
sq_newtableType __sq_newtable;
|
||||
sq_newslotType __sq_newslot;
|
||||
|
||||
sq_pushroottableType __sq_pushroottable;
|
||||
sq_pushstringType __sq_pushstring;
|
||||
sq_pushintegerType __sq_pushinteger;
|
||||
sq_pushfloatType __sq_pushfloat;
|
||||
sq_pushboolType __sq_pushbool;
|
||||
sq_pushassetType __sq_pushasset;
|
||||
sq_pushvectorType __sq_pushvector;
|
||||
sq_pushobjectType __sq_pushobject;
|
||||
|
||||
sq_getstringType __sq_getstring;
|
||||
sq_getintegerType __sq_getinteger;
|
||||
sq_getfloatType __sq_getfloat;
|
||||
sq_getboolType __sq_getbool;
|
||||
sq_getType __sq_get;
|
||||
sq_getassetType __sq_getasset;
|
||||
sq_getuserdataType __sq_getuserdata;
|
||||
sq_getvectorType __sq_getvector;
|
||||
sq_getthisentityType __sq_getthisentity;
|
||||
sq_getobjectType __sq_getobject;
|
||||
|
||||
sq_stackinfosType __sq_stackinfos;
|
||||
|
||||
sq_createuserdataType __sq_createuserdata;
|
||||
sq_setuserdatatypeidType __sq_setuserdatatypeid;
|
||||
sq_getfunctionType __sq_getfunction;
|
||||
|
||||
sq_schedule_call_externalType __sq_schedule_call_external;
|
||||
|
||||
sq_getentityfrominstanceType __sq_getentityfrominstance;
|
||||
sq_GetEntityConstantType __sq_GetEntityConstant_CBaseEntity;
|
||||
|
||||
sq_pushnewstructinstanceType __sq_pushnewstructinstance;
|
||||
sq_sealstructslotType __sq_sealstructslot;
|
||||
};
|
||||
|
||||
struct MessageSource
|
||||
{
|
||||
const char* file;
|
||||
const char* func;
|
||||
int line;
|
||||
};
|
||||
|
||||
// This is a modified version of spdlog::details::log_msg
|
||||
// This is so that we can make it cross DLL boundaries
|
||||
struct LogMsg
|
||||
{
|
||||
int level;
|
||||
uint64_t timestamp;
|
||||
const char* msg;
|
||||
MessageSource source;
|
||||
int pluginHandle;
|
||||
};
|
||||
|
||||
extern "C"
|
||||
{
|
||||
typedef void (*loggerfunc_t)(LogMsg* msg);
|
||||
typedef void (*PLUGIN_RELAY_INVITE_TYPE)(const char* invite);
|
||||
typedef void* (*CreateObjectFunc)(ObjectType type);
|
||||
|
||||
typedef void (*PluginFnCommandCallback_t)(void* command);
|
||||
typedef void (*PluginConCommandConstructorType)(
|
||||
void* newCommand, const char* name, PluginFnCommandCallback_t callback, const char* helpString, int flags, void* parent);
|
||||
typedef void (*PluginConVarRegisterType)(
|
||||
void* pConVar,
|
||||
const char* pszName,
|
||||
const char* pszDefaultValue,
|
||||
int nFlags,
|
||||
const char* pszHelpString,
|
||||
bool bMin,
|
||||
float fMin,
|
||||
bool bMax,
|
||||
float fMax,
|
||||
void* pCallback);
|
||||
typedef void (*PluginConVarMallocType)(void* pConVarMaloc, int a2, int a3);
|
||||
}
|
||||
|
||||
struct PluginNorthstarData
|
||||
{
|
||||
const char* version;
|
||||
HMODULE northstarModule;
|
||||
int pluginHandle;
|
||||
};
|
||||
|
||||
struct PluginInitFuncs
|
||||
{
|
||||
loggerfunc_t logger;
|
||||
PLUGIN_RELAY_INVITE_TYPE relayInviteFunc;
|
||||
CreateObjectFunc createObject;
|
||||
};
|
||||
|
||||
struct PluginEngineData
|
||||
{
|
||||
PluginConCommandConstructorType ConCommandConstructor;
|
||||
PluginConVarMallocType conVarMalloc;
|
||||
PluginConVarRegisterType conVarRegister;
|
||||
void* ConVar_Vtable;
|
||||
void* IConVar_Vtable;
|
||||
void* g_pCVar;
|
||||
};
|
||||
|
||||
/// <summary> Async communication within the plugin system
|
||||
/// Due to the asynchronous nature of plugins, combined with the limitations of multi-compiler support
|
||||
/// and the custom memory allocator used by r2, is it difficult to safely get data across DLL boundaries
|
||||
/// from Northstar to plugin unless Northstar can own that memory.
|
||||
/// This means that plugins should manage their own memory and can only receive data from northstar using one of the functions below.
|
||||
/// These should be exports of the plugin DLL. If they are not exported, they will not be called.
|
||||
/// Note that it is not required to have these exports if you do not use them.
|
||||
/// </summary>
|
||||
|
||||
// Northstar -> Plugin
|
||||
typedef void (*PLUGIN_INIT_TYPE)(PluginInitFuncs* funcs, PluginNorthstarData* data);
|
||||
typedef void (*PLUGIN_INIT_SQVM_TYPE)(SquirrelFunctions* funcs);
|
||||
typedef void (*PLUGIN_INFORM_SQVM_CREATED_TYPE)(ScriptContext context, CSquirrelVM* sqvm);
|
||||
typedef void (*PLUGIN_INFORM_SQVM_DESTROYED_TYPE)(ScriptContext context);
|
||||
|
||||
typedef void (*PLUGIN_INFORM_DLL_LOAD_TYPE)(const char* dll, PluginEngineData* data, void* dllPtr);
|
||||
typedef void (*PLUGIN_RUNFRAME)();
|
|
@ -1,50 +0,0 @@
|
|||
#include "pluginbackend.h"
|
||||
#include "plugin_abi.h"
|
||||
#include "server/serverpresence.h"
|
||||
#include "masterserver/masterserver.h"
|
||||
#include "squirrel/squirrel.h"
|
||||
#include "plugins.h"
|
||||
|
||||
#include "tier1/cmd.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#define EXPORT extern "C" __declspec(dllexport)
|
||||
|
||||
AUTOHOOK_INIT()
|
||||
|
||||
PluginCommunicationHandler* g_pPluginCommunicationhandler;
|
||||
|
||||
static PluginDataRequest storedRequest {PluginDataRequestType::END, (PluginRespondDataCallable) nullptr};
|
||||
|
||||
void PluginCommunicationHandler::RunFrame()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(requestMutex);
|
||||
if (!requestQueue.empty())
|
||||
{
|
||||
storedRequest = requestQueue.front();
|
||||
switch (storedRequest.type)
|
||||
{
|
||||
default:
|
||||
spdlog::error("{} was called with invalid request type '{}'", __FUNCTION__, static_cast<int>(storedRequest.type));
|
||||
}
|
||||
requestQueue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void PluginCommunicationHandler::PushRequest(PluginDataRequestType type, PluginRespondDataCallable func)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(requestMutex);
|
||||
requestQueue.push(PluginDataRequest {type, func});
|
||||
}
|
||||
|
||||
void InformPluginsDLLLoad(fs::path dllPath, void* address)
|
||||
{
|
||||
std::string dllName = dllPath.filename().string();
|
||||
|
||||
void* data = NULL;
|
||||
if (strncmp(dllName.c_str(), "engine.dll", 10) == 0)
|
||||
data = &g_pPluginCommunicationhandler->m_sEngineData;
|
||||
|
||||
g_pPluginManager->InformDLLLoad(dllName.c_str(), data, address);
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
#pragma once
|
||||
#include "plugin_abi.h"
|
||||
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
|
||||
enum PluginDataRequestType
|
||||
{
|
||||
END = 0,
|
||||
};
|
||||
|
||||
union PluginRespondDataCallable
|
||||
{
|
||||
// Empty for now
|
||||
void* UNUSED;
|
||||
};
|
||||
|
||||
class PluginDataRequest
|
||||
{
|
||||
public:
|
||||
PluginDataRequestType type;
|
||||
PluginRespondDataCallable func;
|
||||
PluginDataRequest(PluginDataRequestType type, PluginRespondDataCallable func) : type(type), func(func) {}
|
||||
};
|
||||
|
||||
class PluginCommunicationHandler
|
||||
{
|
||||
public:
|
||||
void RunFrame();
|
||||
void PushRequest(PluginDataRequestType type, PluginRespondDataCallable func);
|
||||
|
||||
public:
|
||||
std::queue<PluginDataRequest> requestQueue = {};
|
||||
std::mutex requestMutex;
|
||||
|
||||
PluginEngineData m_sEngineData {};
|
||||
};
|
||||
|
||||
void InformPluginsDLLLoad(fs::path dllPath, void* address);
|
||||
extern PluginCommunicationHandler* g_pPluginCommunicationhandler;
|
|
@ -0,0 +1,184 @@
|
|||
#include "pluginmanager.h"
|
||||
|
||||
#include <regex>
|
||||
#include "plugins.h"
|
||||
#include "config/profile.h"
|
||||
#include "tier1/cmd.h"
|
||||
|
||||
PluginManager* g_pPluginManager;
|
||||
|
||||
const std::vector<Plugin>& PluginManager::GetLoadedPlugins() const
|
||||
{
|
||||
return this->plugins;
|
||||
}
|
||||
|
||||
const std::optional<Plugin> PluginManager::GetPlugin(HMODULE handle) const
|
||||
{
|
||||
for (const Plugin& plugin : GetLoadedPlugins())
|
||||
if (plugin.m_handle == handle)
|
||||
return plugin;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void PluginManager::LoadPlugin(fs::path path, bool reloaded)
|
||||
{
|
||||
Plugin plugin = Plugin(path.string());
|
||||
|
||||
if (!plugin.IsValid())
|
||||
{
|
||||
NS::log::PLUGINSYS->warn("Unloading invalid plugin '{}'", path.string());
|
||||
plugin.Unload();
|
||||
return;
|
||||
}
|
||||
|
||||
plugins.push_back(plugin);
|
||||
plugin.Init(reloaded);
|
||||
}
|
||||
|
||||
inline void FindPlugins(fs::path pluginPath, std::vector<fs::path>& paths)
|
||||
{
|
||||
// ensure dirs exist
|
||||
if (!fs::exists(pluginPath) || !fs::is_directory(pluginPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (const fs::directory_entry& entry : fs::directory_iterator(pluginPath))
|
||||
{
|
||||
if (fs::is_regular_file(entry) && entry.path().extension() == ".dll")
|
||||
paths.emplace_back(entry.path());
|
||||
}
|
||||
}
|
||||
|
||||
bool PluginManager::LoadPlugins(bool reloaded)
|
||||
{
|
||||
if (strstr(GetCommandLineA(), "-noplugins") != NULL)
|
||||
{
|
||||
NS::log::PLUGINSYS->warn("-noplugins detected; skipping loading plugins");
|
||||
return false;
|
||||
}
|
||||
|
||||
fs::create_directories(GetThunderstoreModFolderPath());
|
||||
|
||||
std::vector<fs::path> paths;
|
||||
|
||||
pluginPath = GetNorthstarPrefix() + "\\plugins";
|
||||
|
||||
fs::path libPath = fs::absolute(pluginPath + "\\lib");
|
||||
if (fs::exists(libPath) && fs::is_directory(libPath))
|
||||
AddDllDirectory(libPath.wstring().c_str());
|
||||
|
||||
FindPlugins(pluginPath, paths);
|
||||
|
||||
// Special case for Thunderstore mods dir
|
||||
std::filesystem::directory_iterator thunderstoreModsDir = fs::directory_iterator(GetThunderstoreModFolderPath());
|
||||
// Set up regex for `AUTHOR-MOD-VERSION` pattern
|
||||
std::regex pattern(R"(.*\\([a-zA-Z0-9_]+)-([a-zA-Z0-9_]+)-(\d+\.\d+\.\d+))");
|
||||
for (fs::directory_entry dir : thunderstoreModsDir)
|
||||
{
|
||||
fs::path pluginsDir = dir.path() / "plugins";
|
||||
// Use regex to match `AUTHOR-MOD-VERSION` pattern
|
||||
if (!std::regex_match(dir.path().string(), pattern))
|
||||
{
|
||||
spdlog::warn("The following directory did not match 'AUTHOR-MOD-VERSION': {}", dir.path().string());
|
||||
continue; // skip loading package that doesn't match
|
||||
}
|
||||
|
||||
fs::path libDir = fs::absolute(pluginsDir / "lib");
|
||||
if (fs::exists(libDir) && fs::is_directory(libDir))
|
||||
AddDllDirectory(libDir.wstring().c_str());
|
||||
|
||||
FindPlugins(pluginsDir, paths);
|
||||
}
|
||||
|
||||
if (paths.empty())
|
||||
{
|
||||
NS::log::PLUGINSYS->warn("Could not find any plugins. Skipped loading plugins");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (fs::path path : paths)
|
||||
{
|
||||
LoadPlugin(path, reloaded);
|
||||
}
|
||||
|
||||
InformAllPluginsInitialized();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PluginManager::ReloadPlugins()
|
||||
{
|
||||
for (const Plugin& plugin : this->GetLoadedPlugins())
|
||||
{
|
||||
plugin.Unload();
|
||||
}
|
||||
|
||||
this->plugins.clear();
|
||||
this->LoadPlugins(true);
|
||||
}
|
||||
|
||||
void PluginManager::RemovePlugin(HMODULE handle)
|
||||
{
|
||||
for (size_t i = 0; i < plugins.size(); i++)
|
||||
{
|
||||
Plugin* plugin = &plugins[i];
|
||||
if (plugin->m_handle == handle)
|
||||
{
|
||||
plugins.erase(plugins.begin() + i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PluginManager::InformAllPluginsInitialized() const
|
||||
{
|
||||
for (const Plugin& plugin : GetLoadedPlugins())
|
||||
{
|
||||
plugin.Finalize();
|
||||
}
|
||||
}
|
||||
|
||||
void PluginManager::InformSqvmCreated(CSquirrelVM* sqvm) const
|
||||
{
|
||||
for (const Plugin& plugin : GetLoadedPlugins())
|
||||
{
|
||||
plugin.OnSqvmCreated(sqvm);
|
||||
}
|
||||
}
|
||||
|
||||
void PluginManager::InformSqvmDestroying(CSquirrelVM* sqvm) const
|
||||
{
|
||||
for (const Plugin& plugin : GetLoadedPlugins())
|
||||
{
|
||||
plugin.OnSqvmDestroying(sqvm);
|
||||
}
|
||||
}
|
||||
|
||||
void PluginManager::InformDllLoad(HMODULE module, fs::path path) const
|
||||
{
|
||||
std::string fn = path.filename().string(); // without this the string gets freed immediately lmao
|
||||
const char* filename = fn.c_str();
|
||||
for (const Plugin& plugin : GetLoadedPlugins())
|
||||
{
|
||||
plugin.OnLibraryLoaded(module, filename);
|
||||
}
|
||||
}
|
||||
|
||||
void PluginManager::RunFrame() const
|
||||
{
|
||||
for (const Plugin& plugin : GetLoadedPlugins())
|
||||
{
|
||||
plugin.RunFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void ConCommand_reload_plugins(const CCommand& args)
|
||||
{
|
||||
g_pPluginManager->ReloadPlugins();
|
||||
}
|
||||
|
||||
ON_DLL_LOAD_RELIESON("engine.dll", PluginManager, ConCommand, (CModule module))
|
||||
{
|
||||
RegisterConCommand("reload_plugins", ConCommand_reload_plugins, "reloads plugins", FCVAR_NONE);
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef PLUGIN_MANAGER_H
|
||||
#define PLUGIN_MANAGER_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
class Plugin;
|
||||
|
||||
class PluginManager
|
||||
{
|
||||
public:
|
||||
const std::vector<Plugin>& GetLoadedPlugins() const;
|
||||
const std::optional<Plugin> GetPlugin(HMODULE handle) const;
|
||||
bool LoadPlugins(bool reloaded = false);
|
||||
void LoadPlugin(fs::path path, bool reloaded = false);
|
||||
void ReloadPlugins();
|
||||
void RemovePlugin(HMODULE handle);
|
||||
|
||||
// callback triggers
|
||||
void InformSqvmCreated(CSquirrelVM* sqvm) const;
|
||||
void InformSqvmDestroying(CSquirrelVM* sqvm) const;
|
||||
void InformDllLoad(HMODULE module, fs::path path) const;
|
||||
void RunFrame() const;
|
||||
|
||||
private:
|
||||
void InformAllPluginsInitialized() const;
|
||||
|
||||
std::vector<Plugin> plugins;
|
||||
std::string pluginPath;
|
||||
};
|
||||
|
||||
extern PluginManager* g_pPluginManager;
|
||||
|
||||
#endif
|
|
@ -1,340 +1,233 @@
|
|||
#include "plugins.h"
|
||||
#include "config/profile.h"
|
||||
|
||||
#include "pluginmanager.h"
|
||||
#include "squirrel/squirrel.h"
|
||||
#include "plugins.h"
|
||||
#include "masterserver/masterserver.h"
|
||||
#include "tier1/convar.h"
|
||||
#include "server/serverpresence.h"
|
||||
#include <optional>
|
||||
#include <regex>
|
||||
|
||||
#include "util/version.h"
|
||||
#include "pluginbackend.h"
|
||||
#include "util/wininfo.h"
|
||||
#include "core/sourceinterface.h"
|
||||
#include "logging/logging.h"
|
||||
#include "dedicated/dedicated.h"
|
||||
|
||||
PluginManager* g_pPluginManager;
|
||||
|
||||
void freeLibrary(HMODULE hLib)
|
||||
bool isValidSquirrelIdentifier(std::string s)
|
||||
{
|
||||
if (!FreeLibrary(hLib))
|
||||
if (!s.size())
|
||||
return false; // identifiers can't be empty
|
||||
if (s[0] <= 57)
|
||||
return false; // identifier can't start with a number
|
||||
for (char& c : s)
|
||||
{
|
||||
spdlog::error("There was an error while trying to free library");
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT void PLUGIN_LOG(LogMsg* msg)
|
||||
{
|
||||
spdlog::source_loc src {};
|
||||
src.filename = msg->source.file;
|
||||
src.funcname = msg->source.func;
|
||||
src.line = msg->source.line;
|
||||
auto&& logger = g_pPluginManager->m_vLoadedPlugins[msg->pluginHandle].logger;
|
||||
logger->log(src, (spdlog::level::level_enum)msg->level, msg->msg);
|
||||
}
|
||||
|
||||
EXPORT void* CreateObject(ObjectType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ObjectType::CONVAR:
|
||||
return (void*)new ConVar;
|
||||
case ObjectType::CONCOMMANDS:
|
||||
return (void*)new ConCommand;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Plugin> PluginManager::LoadPlugin(fs::path path, PluginInitFuncs* funcs, PluginNorthstarData* data)
|
||||
{
|
||||
|
||||
Plugin plugin {};
|
||||
|
||||
std::string pathstring = path.string();
|
||||
std::wstring wpath = path.wstring();
|
||||
|
||||
LPCWSTR wpptr = wpath.c_str();
|
||||
HMODULE datafile = LoadLibraryExW(wpptr, 0, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); // Load the DLL as a data file
|
||||
if (datafile == NULL)
|
||||
{
|
||||
NS::log::PLUGINSYS->info("Failed to load library '{}': ", std::system_category().message(GetLastError()));
|
||||
return std::nullopt;
|
||||
}
|
||||
HRSRC manifestResource = FindResourceW(datafile, MAKEINTRESOURCEW(IDR_RCDATA1), RT_RCDATA);
|
||||
|
||||
if (manifestResource == NULL)
|
||||
{
|
||||
NS::log::PLUGINSYS->info("Could not find manifest for library '{}'", pathstring);
|
||||
freeLibrary(datafile);
|
||||
return std::nullopt;
|
||||
}
|
||||
HGLOBAL myResourceData = LoadResource(datafile, manifestResource);
|
||||
if (myResourceData == NULL)
|
||||
{
|
||||
NS::log::PLUGINSYS->error("Failed to load manifest from library '{}'", pathstring);
|
||||
freeLibrary(datafile);
|
||||
return std::nullopt;
|
||||
}
|
||||
int manifestSize = SizeofResource(datafile, manifestResource);
|
||||
std::string manifest = std::string((const char*)LockResource(myResourceData), 0, manifestSize);
|
||||
freeLibrary(datafile);
|
||||
|
||||
rapidjson_document manifestJSON;
|
||||
manifestJSON.Parse(manifest.c_str());
|
||||
|
||||
if (manifestJSON.HasParseError())
|
||||
{
|
||||
NS::log::PLUGINSYS->error("Manifest for '{}' was invalid", pathstring);
|
||||
return std::nullopt;
|
||||
}
|
||||
if (!manifestJSON.HasMember("name"))
|
||||
{
|
||||
NS::log::PLUGINSYS->error("'{}' is missing a name in its manifest", pathstring);
|
||||
return std::nullopt;
|
||||
}
|
||||
if (!manifestJSON.HasMember("displayname"))
|
||||
{
|
||||
NS::log::PLUGINSYS->error("'{}' is missing a displayname in its manifest", pathstring);
|
||||
return std::nullopt;
|
||||
}
|
||||
if (!manifestJSON.HasMember("description"))
|
||||
{
|
||||
NS::log::PLUGINSYS->error("'{}' is missing a description in its manifest", pathstring);
|
||||
return std::nullopt;
|
||||
}
|
||||
if (!manifestJSON.HasMember("api_version"))
|
||||
{
|
||||
NS::log::PLUGINSYS->error("'{}' is missing a api_version in its manifest", pathstring);
|
||||
return std::nullopt;
|
||||
}
|
||||
if (!manifestJSON.HasMember("version"))
|
||||
{
|
||||
NS::log::PLUGINSYS->error("'{}' is missing a version in its manifest", pathstring);
|
||||
return std::nullopt;
|
||||
}
|
||||
if (!manifestJSON.HasMember("run_on_server"))
|
||||
{
|
||||
NS::log::PLUGINSYS->error("'{}' is missing 'run_on_server' in its manifest", pathstring);
|
||||
return std::nullopt;
|
||||
}
|
||||
if (!manifestJSON.HasMember("run_on_client"))
|
||||
{
|
||||
NS::log::PLUGINSYS->error("'{}' is missing 'run_on_client' in its manifest", pathstring);
|
||||
return std::nullopt;
|
||||
}
|
||||
auto test = manifestJSON["api_version"].GetString();
|
||||
if (strcmp(manifestJSON["api_version"].GetString(), std::to_string(ABI_VERSION).c_str()))
|
||||
{
|
||||
NS::log::PLUGINSYS->error(
|
||||
"'{}' has an incompatible API version number in its manifest. Current ABI version is '{}'", pathstring, ABI_VERSION);
|
||||
return std::nullopt;
|
||||
}
|
||||
// Passed all checks, going to actually load it now
|
||||
|
||||
HMODULE pluginLib =
|
||||
LoadLibraryExW(wpptr, 0, LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); // Load the DLL with lib folders
|
||||
if (pluginLib == NULL)
|
||||
{
|
||||
NS::log::PLUGINSYS->info("Failed to load library '{}': ", std::system_category().message(GetLastError()));
|
||||
return std::nullopt;
|
||||
}
|
||||
plugin.init = (PLUGIN_INIT_TYPE)GetProcAddress(pluginLib, "PLUGIN_INIT");
|
||||
if (plugin.init == NULL)
|
||||
{
|
||||
NS::log::PLUGINSYS->info("Library '{}' has no function 'PLUGIN_INIT'", pathstring);
|
||||
return std::nullopt;
|
||||
}
|
||||
NS::log::PLUGINSYS->info("Succesfully loaded {}", pathstring);
|
||||
|
||||
plugin.name = manifestJSON["name"].GetString();
|
||||
plugin.displayName = manifestJSON["displayname"].GetString();
|
||||
plugin.description = manifestJSON["description"].GetString();
|
||||
plugin.api_version = manifestJSON["api_version"].GetString();
|
||||
plugin.version = manifestJSON["version"].GetString();
|
||||
|
||||
plugin.run_on_client = manifestJSON["run_on_client"].GetBool();
|
||||
plugin.run_on_server = manifestJSON["run_on_server"].GetBool();
|
||||
|
||||
if (!plugin.run_on_server && IsDedicatedServer())
|
||||
return std::nullopt;
|
||||
|
||||
if (manifestJSON.HasMember("dependencyName"))
|
||||
{
|
||||
plugin.dependencyName = manifestJSON["dependencyName"].GetString();
|
||||
}
|
||||
else
|
||||
{
|
||||
plugin.dependencyName = plugin.name;
|
||||
}
|
||||
|
||||
if (std::find_if(
|
||||
plugin.dependencyName.begin(),
|
||||
plugin.dependencyName.end(),
|
||||
[&](char c) -> bool { return !((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'); }) !=
|
||||
plugin.dependencyName.end())
|
||||
{
|
||||
NS::log::PLUGINSYS->warn("Dependency string \"{}\" in {} is not valid a squirrel constant!", plugin.dependencyName, plugin.name);
|
||||
}
|
||||
|
||||
plugin.init_sqvm_client = (PLUGIN_INIT_SQVM_TYPE)GetProcAddress(pluginLib, "PLUGIN_INIT_SQVM_CLIENT");
|
||||
plugin.init_sqvm_server = (PLUGIN_INIT_SQVM_TYPE)GetProcAddress(pluginLib, "PLUGIN_INIT_SQVM_SERVER");
|
||||
plugin.inform_sqvm_created = (PLUGIN_INFORM_SQVM_CREATED_TYPE)GetProcAddress(pluginLib, "PLUGIN_INFORM_SQVM_CREATED");
|
||||
plugin.inform_sqvm_destroyed = (PLUGIN_INFORM_SQVM_DESTROYED_TYPE)GetProcAddress(pluginLib, "PLUGIN_INFORM_SQVM_DESTROYED");
|
||||
|
||||
plugin.inform_dll_load = (PLUGIN_INFORM_DLL_LOAD_TYPE)GetProcAddress(pluginLib, "PLUGIN_INFORM_DLL_LOAD");
|
||||
|
||||
plugin.run_frame = (PLUGIN_RUNFRAME)GetProcAddress(pluginLib, "PLUGIN_RUNFRAME");
|
||||
|
||||
plugin.handle = (int)m_vLoadedPlugins.size();
|
||||
plugin.logger = std::make_shared<ColoredLogger>(plugin.displayName.c_str(), NS::Colors::PLUGIN);
|
||||
RegisterLogger(plugin.logger);
|
||||
NS::log::PLUGINSYS->info("Loading plugin {} version {}", plugin.displayName, plugin.version);
|
||||
m_vLoadedPlugins.push_back(plugin);
|
||||
|
||||
plugin.init(funcs, data);
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
inline void FindPlugins(fs::path pluginPath, std::vector<fs::path>& paths)
|
||||
{
|
||||
// ensure dirs exist
|
||||
if (!fs::exists(pluginPath) || !fs::is_directory(pluginPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (const fs::directory_entry& entry : fs::directory_iterator(pluginPath))
|
||||
{
|
||||
if (fs::is_regular_file(entry) && entry.path().extension() == ".dll")
|
||||
paths.emplace_back(entry.path());
|
||||
}
|
||||
}
|
||||
|
||||
bool PluginManager::LoadPlugins()
|
||||
{
|
||||
if (strstr(GetCommandLineA(), "-noplugins") != NULL)
|
||||
{
|
||||
NS::log::PLUGINSYS->warn("-noplugins detected; skipping loading plugins");
|
||||
// only allow underscores, 0-9, A-Z and a-z
|
||||
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_')
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
|
||||
fs::create_directories(GetThunderstoreModFolderPath());
|
||||
|
||||
std::vector<fs::path> paths;
|
||||
|
||||
pluginPath = GetNorthstarPrefix() + "\\plugins";
|
||||
|
||||
PluginNorthstarData data {};
|
||||
std::string ns_version {version};
|
||||
|
||||
PluginInitFuncs funcs {};
|
||||
funcs.logger = PLUGIN_LOG;
|
||||
funcs.relayInviteFunc = nullptr;
|
||||
funcs.createObject = CreateObject;
|
||||
|
||||
data.version = ns_version.c_str();
|
||||
data.northstarModule = g_NorthstarModule;
|
||||
|
||||
fs::path libPath = fs::absolute(pluginPath + "\\lib");
|
||||
if (fs::exists(libPath) && fs::is_directory(libPath))
|
||||
AddDllDirectory(libPath.wstring().c_str());
|
||||
|
||||
FindPlugins(pluginPath, paths);
|
||||
|
||||
// Special case for Thunderstore mods dir
|
||||
std::filesystem::directory_iterator thunderstoreModsDir = fs::directory_iterator(GetThunderstoreModFolderPath());
|
||||
// Set up regex for `AUTHOR-MOD-VERSION` pattern
|
||||
std::regex pattern(R"(.*\\([a-zA-Z0-9_]+)-([a-zA-Z0-9_]+)-(\d+\.\d+\.\d+))");
|
||||
for (fs::directory_entry dir : thunderstoreModsDir)
|
||||
{
|
||||
fs::path pluginsDir = dir.path() / "plugins";
|
||||
// Use regex to match `AUTHOR-MOD-VERSION` pattern
|
||||
if (!std::regex_match(dir.path().string(), pattern))
|
||||
{
|
||||
spdlog::warn("The following directory did not match 'AUTHOR-MOD-VERSION': {}", dir.path().string());
|
||||
continue; // skip loading package that doesn't match
|
||||
}
|
||||
|
||||
fs::path libDir = fs::absolute(pluginsDir / "lib");
|
||||
if (fs::exists(libDir) && fs::is_directory(libDir))
|
||||
AddDllDirectory(libDir.wstring().c_str());
|
||||
|
||||
FindPlugins(pluginsDir, paths);
|
||||
}
|
||||
|
||||
if (paths.empty())
|
||||
{
|
||||
NS::log::PLUGINSYS->warn("Could not find any plugins. Skipped loading plugins");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (fs::path path : paths)
|
||||
{
|
||||
if (LoadPlugin(path, &funcs, &data))
|
||||
data.pluginHandle += 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PluginManager::InformSQVMLoad(ScriptContext context, SquirrelFunctions* s)
|
||||
Plugin::Plugin(std::string path) : m_location(path)
|
||||
{
|
||||
for (auto plugin : m_vLoadedPlugins)
|
||||
HMODULE pluginModule = GetModuleHandleA(path.c_str());
|
||||
|
||||
if (pluginModule)
|
||||
{
|
||||
if (context == ScriptContext::CLIENT && plugin.init_sqvm_client != NULL)
|
||||
{
|
||||
plugin.init_sqvm_client(s);
|
||||
}
|
||||
else if (context == ScriptContext::SERVER && plugin.init_sqvm_server != NULL)
|
||||
{
|
||||
plugin.init_sqvm_server(s);
|
||||
}
|
||||
// plugins may refuse to get unloaded for any reason so we need to prevent them getting loaded twice when reloading plugins
|
||||
NS::log::PLUGINSYS->warn("Plugin has already been loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
m_handle = LoadLibraryExA(path.c_str(), 0, LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
|
||||
|
||||
NS::log::PLUGINSYS->info("loaded plugin handle {}", static_cast<void*>(m_handle));
|
||||
|
||||
if (!m_handle)
|
||||
{
|
||||
NS::log::PLUGINSYS->error("Failed to load plugin '{}' (Error: {})", path, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
m_initData = {.pluginHandle = m_handle};
|
||||
|
||||
CreateInterfaceFn CreatePluginInterface = (CreateInterfaceFn)GetProcAddress(m_handle, "CreateInterface");
|
||||
|
||||
if (!CreatePluginInterface)
|
||||
{
|
||||
NS::log::PLUGINSYS->error("Plugin at '{}' does not expose CreateInterface()", path);
|
||||
return;
|
||||
}
|
||||
|
||||
m_pluginId = (IPluginId*)CreatePluginInterface(PLUGIN_ID_VERSION, 0);
|
||||
|
||||
if (!m_pluginId)
|
||||
{
|
||||
NS::log::PLUGINSYS->error("Could not load IPluginId interface of plugin at '{}'", path);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* name = m_pluginId->GetString(PluginString::NAME);
|
||||
const char* logName = m_pluginId->GetString(PluginString::LOG_NAME);
|
||||
const char* dependencyName = m_pluginId->GetString(PluginString::DEPENDENCY_NAME);
|
||||
int64_t context = m_pluginId->GetField(PluginField::CONTEXT);
|
||||
|
||||
m_runOnServer = context & PluginContext::DEDICATED;
|
||||
m_runOnClient = context & PluginContext::CLIENT;
|
||||
|
||||
m_name = std::string(name);
|
||||
m_logName = std::string(logName);
|
||||
m_dependencyName = std::string(dependencyName);
|
||||
|
||||
if (!name)
|
||||
{
|
||||
NS::log::PLUGINSYS->error("Could not load name of plugin at '{}'", path);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!logName)
|
||||
{
|
||||
NS::log::PLUGINSYS->error("Could not load logName of plugin {}", name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dependencyName)
|
||||
{
|
||||
NS::log::PLUGINSYS->error("Could not load dependencyName of plugin {}", name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isValidSquirrelIdentifier(m_dependencyName))
|
||||
{
|
||||
NS::log::PLUGINSYS->error("Dependency name \"{}\" of plugin {} is not valid", dependencyName, name);
|
||||
return;
|
||||
}
|
||||
|
||||
m_callbacks = (IPluginCallbacks*)CreatePluginInterface("PluginCallbacks001", 0);
|
||||
|
||||
if (!m_callbacks)
|
||||
{
|
||||
NS::log::PLUGINSYS->error("Could not create callback interface of plugin {}", name);
|
||||
return;
|
||||
}
|
||||
|
||||
m_logger = std::make_shared<ColoredLogger>(m_logName, NS::Colors::PLUGIN);
|
||||
RegisterLogger(m_logger);
|
||||
|
||||
if (IsDedicatedServer() && !m_runOnServer)
|
||||
{
|
||||
NS::log::PLUGINSYS->info("Unloading {} because it's not supposed to run on dedicated servers", m_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsDedicatedServer() && !m_runOnClient)
|
||||
{
|
||||
NS::log::PLUGINSYS->info("Unloading {} because it's only supposed to run on dedicated servers", m_name);
|
||||
return;
|
||||
}
|
||||
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
void PluginManager::InformSQVMCreated(ScriptContext context, CSquirrelVM* sqvm)
|
||||
bool Plugin::Unload() const
|
||||
{
|
||||
for (auto plugin : m_vLoadedPlugins)
|
||||
if (!m_handle)
|
||||
return true;
|
||||
|
||||
if (IsValid())
|
||||
{
|
||||
if (plugin.inform_sqvm_created != NULL)
|
||||
{
|
||||
plugin.inform_sqvm_created(context, sqvm);
|
||||
}
|
||||
bool unloaded = m_callbacks->Unload();
|
||||
|
||||
if (!unloaded)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!FreeLibrary(m_handle))
|
||||
{
|
||||
NS::log::PLUGINSYS->error("Failed to unload plugin at '{}'", m_location);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_pPluginManager->RemovePlugin(m_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PluginManager::InformSQVMDestroyed(ScriptContext context)
|
||||
void Plugin::Reload() const
|
||||
{
|
||||
for (auto plugin : m_vLoadedPlugins)
|
||||
{
|
||||
if (plugin.inform_sqvm_destroyed != NULL)
|
||||
{
|
||||
plugin.inform_sqvm_destroyed(context);
|
||||
}
|
||||
}
|
||||
bool unloaded = Unload();
|
||||
|
||||
if (!unloaded)
|
||||
return;
|
||||
|
||||
g_pPluginManager->LoadPlugin(fs::path(m_location), true);
|
||||
}
|
||||
|
||||
void PluginManager::InformDLLLoad(const char* dll, void* data, void* dllPtr)
|
||||
void Plugin::Log(spdlog::level::level_enum level, char* msg) const
|
||||
{
|
||||
for (auto plugin : m_vLoadedPlugins)
|
||||
{
|
||||
if (plugin.inform_dll_load != NULL)
|
||||
{
|
||||
plugin.inform_dll_load(dll, (PluginEngineData*)data, dllPtr);
|
||||
}
|
||||
}
|
||||
m_logger->log(level, msg);
|
||||
}
|
||||
|
||||
void PluginManager::RunFrame()
|
||||
bool Plugin::IsValid() const
|
||||
{
|
||||
for (auto plugin : m_vLoadedPlugins)
|
||||
{
|
||||
if (plugin.run_frame != NULL)
|
||||
{
|
||||
plugin.run_frame();
|
||||
}
|
||||
}
|
||||
return m_valid && m_pCreateInterface && m_pluginId && m_callbacks && m_handle;
|
||||
}
|
||||
|
||||
const std::string& Plugin::GetName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
const std::string& Plugin::GetLogName() const
|
||||
{
|
||||
return m_logName;
|
||||
}
|
||||
|
||||
const std::string& Plugin::GetDependencyName() const
|
||||
{
|
||||
return m_dependencyName;
|
||||
}
|
||||
|
||||
const std::string& Plugin::GetLocation() const
|
||||
{
|
||||
return m_location;
|
||||
}
|
||||
|
||||
bool Plugin::ShouldRunOnServer() const
|
||||
{
|
||||
return m_runOnServer;
|
||||
}
|
||||
|
||||
bool Plugin::ShouldRunOnClient() const
|
||||
{
|
||||
return m_runOnClient;
|
||||
}
|
||||
|
||||
void* Plugin::CreateInterface(const char* name, int* status) const
|
||||
{
|
||||
return m_pCreateInterface(name, status);
|
||||
}
|
||||
|
||||
void Plugin::Init(bool reloaded) const
|
||||
{
|
||||
m_callbacks->Init(g_NorthstarModule, &m_initData, reloaded);
|
||||
}
|
||||
|
||||
void Plugin::Finalize() const
|
||||
{
|
||||
m_callbacks->Finalize();
|
||||
}
|
||||
|
||||
void Plugin::OnSqvmCreated(CSquirrelVM* sqvm) const
|
||||
{
|
||||
m_callbacks->OnSqvmCreated(sqvm);
|
||||
}
|
||||
|
||||
void Plugin::OnSqvmDestroying(CSquirrelVM* sqvm) const
|
||||
{
|
||||
NS::log::PLUGINSYS->info("destroying sqvm {}", sqvm->vmContext);
|
||||
m_callbacks->OnSqvmDestroying(sqvm);
|
||||
}
|
||||
|
||||
void Plugin::OnLibraryLoaded(HMODULE module, const char* name) const
|
||||
{
|
||||
m_callbacks->OnLibraryLoaded(module, name);
|
||||
}
|
||||
|
||||
void Plugin::RunFrame() const
|
||||
{
|
||||
m_callbacks->RunFrame();
|
||||
}
|
||||
|
|
|
@ -1,59 +1,50 @@
|
|||
#pragma once
|
||||
#include "plugin_abi.h"
|
||||
|
||||
const int IDR_RCDATA1 = 101;
|
||||
#include "core/sourceinterface.h"
|
||||
#include "plugins/interfaces/interface.h"
|
||||
#include "plugins/interfaces/IPluginId.h"
|
||||
#include "plugins/interfaces/IPluginCallbacks.h"
|
||||
|
||||
class Plugin
|
||||
{
|
||||
public:
|
||||
std::string name;
|
||||
std::string displayName;
|
||||
std::string dependencyName;
|
||||
std::string description;
|
||||
|
||||
std::string api_version;
|
||||
std::string version;
|
||||
|
||||
// For now this is just implemented as the index into the plugins array
|
||||
// Maybe a bit shit but it works
|
||||
int handle;
|
||||
|
||||
std::shared_ptr<ColoredLogger> logger;
|
||||
|
||||
bool run_on_client = false;
|
||||
bool run_on_server = false;
|
||||
|
||||
public:
|
||||
PLUGIN_INIT_TYPE init;
|
||||
PLUGIN_INIT_SQVM_TYPE init_sqvm_client;
|
||||
PLUGIN_INIT_SQVM_TYPE init_sqvm_server;
|
||||
PLUGIN_INFORM_SQVM_CREATED_TYPE inform_sqvm_created;
|
||||
PLUGIN_INFORM_SQVM_DESTROYED_TYPE inform_sqvm_destroyed;
|
||||
|
||||
PLUGIN_INFORM_DLL_LOAD_TYPE inform_dll_load;
|
||||
|
||||
PLUGIN_RUNFRAME run_frame;
|
||||
};
|
||||
|
||||
class PluginManager
|
||||
{
|
||||
public:
|
||||
std::vector<Plugin> m_vLoadedPlugins;
|
||||
|
||||
public:
|
||||
bool LoadPlugins();
|
||||
std::optional<Plugin> LoadPlugin(fs::path path, PluginInitFuncs* funcs, PluginNorthstarData* data);
|
||||
|
||||
void InformSQVMLoad(ScriptContext context, SquirrelFunctions* s);
|
||||
void InformSQVMCreated(ScriptContext context, CSquirrelVM* sqvm);
|
||||
void InformSQVMDestroyed(ScriptContext context);
|
||||
|
||||
void InformDLLLoad(const char* dll, void* data, void* dllPtr);
|
||||
|
||||
void RunFrame();
|
||||
|
||||
private:
|
||||
std::string pluginPath;
|
||||
};
|
||||
CreateInterfaceFn m_pCreateInterface;
|
||||
IPluginId* m_pluginId = 0;
|
||||
IPluginCallbacks* m_callbacks = 0;
|
||||
|
||||
extern PluginManager* g_pPluginManager;
|
||||
std::shared_ptr<ColoredLogger> m_logger;
|
||||
|
||||
bool m_valid = false;
|
||||
std::string m_name;
|
||||
std::string m_logName;
|
||||
std::string m_dependencyName;
|
||||
std::string m_location; // path of the dll
|
||||
bool m_runOnServer;
|
||||
bool m_runOnClient;
|
||||
|
||||
public:
|
||||
HMODULE m_handle;
|
||||
PluginNorthstarData m_initData;
|
||||
|
||||
Plugin(std::string path);
|
||||
bool Unload() const;
|
||||
void Reload() const;
|
||||
|
||||
// sys
|
||||
void Log(spdlog::level::level_enum level, char* msg) const;
|
||||
|
||||
// callbacks
|
||||
bool IsValid() const;
|
||||
const std::string& GetName() const;
|
||||
const std::string& GetLogName() const;
|
||||
const std::string& GetDependencyName() const;
|
||||
const std::string& GetLocation() const;
|
||||
bool ShouldRunOnServer() const;
|
||||
bool ShouldRunOnClient() const;
|
||||
void* CreateInterface(const char* pName, int* pStatus) const;
|
||||
void Init(bool reloaded) const;
|
||||
void Finalize() const;
|
||||
void OnSqvmCreated(CSquirrelVM* sqvm) const;
|
||||
void OnSqvmDestroying(CSquirrelVM* sqvm) const;
|
||||
void OnLibraryLoaded(HMODULE module, const char* name) const;
|
||||
void RunFrame() const;
|
||||
};
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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");
|
||||
}
|
|
@ -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;
|
|
@ -0,0 +1,6 @@
|
|||
#include "ai_navmesh.h"
|
||||
|
||||
ON_DLL_LOAD("server.dll", ServerAiNavMesh, (CModule module))
|
||||
{
|
||||
g_pNavMesh = module.Offset(0x105F5D0).RCast<dtNavMesh**>();
|
||||
}
|
|
@ -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;
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
#include "dedicated/dedicated.h"
|
||||
#include "engine/r2engine.h"
|
||||
#include "core/tier0.h"
|
||||
#include "plugins/plugin_abi.h"
|
||||
#include "plugins/plugins.h"
|
||||
#include "plugins/pluginmanager.h"
|
||||
#include "ns_version.h"
|
||||
#include "core/vanilla.h"
|
||||
|
||||
|
@ -157,79 +157,6 @@ const char* SQTypeNameFromID(int type)
|
|||
return "";
|
||||
}
|
||||
|
||||
template <ScriptContext context> void SquirrelManager<context>::GenerateSquirrelFunctionsStruct(SquirrelFunctions* s)
|
||||
{
|
||||
s->RegisterSquirrelFunc = RegisterSquirrelFunc;
|
||||
s->__sq_defconst = __sq_defconst;
|
||||
|
||||
s->__sq_compilebuffer = __sq_compilebuffer;
|
||||
s->__sq_call = __sq_call;
|
||||
s->__sq_raiseerror = __sq_raiseerror;
|
||||
s->__sq_compilefile = __sq_compilefile;
|
||||
|
||||
s->__sq_newarray = __sq_newarray;
|
||||
s->__sq_arrayappend = __sq_arrayappend;
|
||||
|
||||
s->__sq_newtable = __sq_newtable;
|
||||
s->__sq_newslot = __sq_newslot;
|
||||
|
||||
s->__sq_pushroottable = __sq_pushroottable;
|
||||
s->__sq_pushstring = __sq_pushstring;
|
||||
s->__sq_pushinteger = __sq_pushinteger;
|
||||
s->__sq_pushfloat = __sq_pushfloat;
|
||||
s->__sq_pushbool = __sq_pushbool;
|
||||
s->__sq_pushasset = __sq_pushasset;
|
||||
s->__sq_pushvector = __sq_pushvector;
|
||||
s->__sq_pushobject = __sq_pushobject;
|
||||
|
||||
s->__sq_getstring = __sq_getstring;
|
||||
s->__sq_getinteger = __sq_getinteger;
|
||||
s->__sq_getfloat = __sq_getfloat;
|
||||
s->__sq_getbool = __sq_getbool;
|
||||
s->__sq_get = __sq_get;
|
||||
s->__sq_getasset = __sq_getasset;
|
||||
s->__sq_getuserdata = __sq_getuserdata;
|
||||
s->__sq_getvector = __sq_getvector;
|
||||
s->__sq_getthisentity = __sq_getthisentity;
|
||||
s->__sq_getobject = __sq_getobject;
|
||||
|
||||
s->__sq_stackinfos = __sq_stackinfos;
|
||||
|
||||
s->__sq_createuserdata = __sq_createuserdata;
|
||||
s->__sq_setuserdatatypeid = __sq_setuserdatatypeid;
|
||||
s->__sq_getfunction = __sq_getfunction;
|
||||
|
||||
s->__sq_schedule_call_external = AsyncCall_External;
|
||||
|
||||
s->__sq_getentityfrominstance = __sq_getentityfrominstance;
|
||||
s->__sq_GetEntityConstant_CBaseEntity = __sq_GetEntityConstant_CBaseEntity;
|
||||
|
||||
s->__sq_pushnewstructinstance = __sq_pushnewstructinstance;
|
||||
s->__sq_sealstructslot = __sq_sealstructslot;
|
||||
}
|
||||
|
||||
// Allows for generating squirrelmessages from plugins.
|
||||
void AsyncCall_External(ScriptContext context, const char* func_name, SquirrelMessage_External_Pop function, void* userdata)
|
||||
{
|
||||
SquirrelMessage message {};
|
||||
message.functionName = func_name;
|
||||
message.isExternal = true;
|
||||
message.externalFunc = function;
|
||||
message.userdata = userdata;
|
||||
switch (context)
|
||||
{
|
||||
case ScriptContext::CLIENT:
|
||||
g_pSquirrel<ScriptContext::CLIENT>->messageBuffer->push(message);
|
||||
break;
|
||||
case ScriptContext::SERVER:
|
||||
g_pSquirrel<ScriptContext::SERVER>->messageBuffer->push(message);
|
||||
break;
|
||||
case ScriptContext::UI:
|
||||
g_pSquirrel<ScriptContext::UI>->messageBuffer->push(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// needed to define implementations for squirrelmanager outside of squirrel.h without compiler errors
|
||||
template class SquirrelManager<ScriptContext::SERVER>;
|
||||
template class SquirrelManager<ScriptContext::CLIENT>;
|
||||
|
@ -264,11 +191,11 @@ template <ScriptContext context> void SquirrelManager<context>::VMCreated(CSquir
|
|||
defconst(m_pSQVM, pair.first.c_str(), bWasFound);
|
||||
}
|
||||
|
||||
auto loadedPlugins = &g_pPluginManager->m_vLoadedPlugins;
|
||||
std::vector<Plugin> loadedPlugins = g_pPluginManager->GetLoadedPlugins();
|
||||
for (const auto& pluginName : g_pModManager->m_PluginDependencyConstants)
|
||||
{
|
||||
auto f = [&](Plugin plugin) -> bool { return plugin.dependencyName == pluginName; };
|
||||
defconst(m_pSQVM, pluginName.c_str(), std::find_if(loadedPlugins->begin(), loadedPlugins->end(), f) != loadedPlugins->end());
|
||||
auto f = [&](Plugin plugin) -> bool { return plugin.GetDependencyName() == pluginName; };
|
||||
defconst(m_pSQVM, pluginName.c_str(), std::find_if(loadedPlugins.begin(), loadedPlugins.end(), f) != loadedPlugins.end());
|
||||
}
|
||||
|
||||
defconst(m_pSQVM, "MAX_FOLDER_SIZE", GetMaxSaveFolderSize() / 1024);
|
||||
|
@ -284,7 +211,7 @@ template <ScriptContext context> void SquirrelManager<context>::VMCreated(CSquir
|
|||
defconst(m_pSQVM, "VANILLA", g_pVanillaCompatibility->GetVanillaCompatibility());
|
||||
|
||||
g_pSquirrel<context>->messageBuffer = new SquirrelMessageBuffer();
|
||||
g_pPluginManager->InformSQVMCreated(context, newSqvm);
|
||||
g_pPluginManager->InformSqvmCreated(newSqvm);
|
||||
}
|
||||
|
||||
template <ScriptContext context> void SquirrelManager<context>::VMDestroyed()
|
||||
|
@ -312,7 +239,7 @@ template <ScriptContext context> void SquirrelManager<context>::VMDestroyed()
|
|||
}
|
||||
}
|
||||
|
||||
g_pPluginManager->InformSQVMDestroyed(context);
|
||||
g_pPluginManager->InformSqvmDestroying(m_pSQVM);
|
||||
|
||||
// Discard the previous vm and delete the message buffer.
|
||||
m_pSQVM = nullptr;
|
||||
|
@ -661,17 +588,10 @@ template <ScriptContext context> void SquirrelManager<context>::ProcessMessageBu
|
|||
|
||||
size_t argsAmount = message.args.size();
|
||||
|
||||
if (message.isExternal && message.externalFunc != NULL)
|
||||
for (auto& v : message.args)
|
||||
{
|
||||
argsAmount = message.externalFunc(m_pSQVM->sqvm, message.userdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto& v : message.args)
|
||||
{
|
||||
// Execute lambda to push arg to stack
|
||||
v();
|
||||
}
|
||||
// Execute lambda to push arg to stack
|
||||
v();
|
||||
}
|
||||
|
||||
_call(m_pSQVM->sqvm, (SQInteger)argsAmount);
|
||||
|
@ -839,10 +759,6 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module))
|
|||
|
||||
g_pSquirrel<ScriptContext::CLIENT>->__sq_getfunction = module.Offset(0x6CB0).RCast<sq_getfunctionType>();
|
||||
g_pSquirrel<ScriptContext::UI>->__sq_getfunction = g_pSquirrel<ScriptContext::CLIENT>->__sq_getfunction;
|
||||
|
||||
SquirrelFunctions s = {};
|
||||
g_pSquirrel<ScriptContext::CLIENT>->GenerateSquirrelFunctionsStruct(&s);
|
||||
g_pPluginManager->InformSQVMLoad(ScriptContext::CLIENT, &s);
|
||||
}
|
||||
|
||||
ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module))
|
||||
|
@ -921,10 +837,6 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module))
|
|||
FCVAR_GAMEDLL | FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS | FCVAR_CHEAT);
|
||||
|
||||
StubUnsafeSQFuncs<ScriptContext::SERVER>();
|
||||
|
||||
SquirrelFunctions s = {};
|
||||
g_pSquirrel<ScriptContext::SERVER>->GenerateSquirrelFunctionsStruct(&s);
|
||||
g_pPluginManager->InformSQVMLoad(ScriptContext::SERVER, &s);
|
||||
}
|
||||
|
||||
void InitialiseSquirrelManagers()
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "squirrelclasstypes.h"
|
||||
#include "squirrelautobind.h"
|
||||
#include "core/math/vector.h"
|
||||
#include "plugins/plugin_abi.h"
|
||||
#include "mods/modmanager.h"
|
||||
|
||||
/*
|
||||
|
@ -51,8 +50,6 @@ const char* GetContextName_Short(ScriptContext context);
|
|||
eSQReturnType SQReturnTypeFromString(const char* pReturnType);
|
||||
const char* SQTypeNameFromID(const int iTypeId);
|
||||
|
||||
void AsyncCall_External(ScriptContext context, const char* func_name, SquirrelMessage_External_Pop function, void* userdata);
|
||||
|
||||
ScriptContext ScriptContextFromString(std::string string);
|
||||
|
||||
namespace NS::log
|
||||
|
@ -417,7 +414,6 @@ public:
|
|||
SQRESULT setupfunc(const SQChar* funcname);
|
||||
void AddFuncOverride(std::string name, SQFunction func);
|
||||
void ProcessMessageBuffer();
|
||||
void GenerateSquirrelFunctionsStruct(SquirrelFunctions* s);
|
||||
};
|
||||
|
||||
template <ScriptContext context> SquirrelManager<context>* g_pSquirrel;
|
||||
|
@ -483,7 +479,7 @@ requires is_iterable<T>
|
|||
inline VoidFunction SQMessageBufferPushArg(T& arg) {
|
||||
FunctionVector localv = {};
|
||||
localv.push_back([]{g_pSquirrel<context>->newarray(g_pSquirrel<context>->m_pSQVM->sqvm, 0);});
|
||||
|
||||
|
||||
for (const auto& item : arg) {
|
||||
localv.push_back(SQMessageBufferPushArg<context>(item));
|
||||
localv.push_back([]{g_pSquirrel<context>->arrayappend(g_pSquirrel<context>->m_pSQVM->sqvm, -2);});
|
||||
|
@ -497,7 +493,7 @@ requires is_map<T>
|
|||
inline VoidFunction SQMessageBufferPushArg(T& map) {
|
||||
FunctionVector localv = {};
|
||||
localv.push_back([]{g_pSquirrel<context>->newtable(g_pSquirrel<context>->m_pSQVM->sqvm);});
|
||||
|
||||
|
||||
for (const auto& item : map) {
|
||||
localv.push_back(SQMessageBufferPushArg<context>(item.first));
|
||||
localv.push_back(SQMessageBufferPushArg<context>(item.second));
|
||||
|
|
|
@ -116,18 +116,11 @@ concept is_iterable = requires(std::ranges::range_value_t<T> x)
|
|||
|
||||
// clang-format on
|
||||
|
||||
typedef int (*SquirrelMessage_External_Pop)(HSquirrelVM* sqvm, void* userdata);
|
||||
typedef void (*sq_schedule_call_externalType)(
|
||||
ScriptContext context, const char* funcname, SquirrelMessage_External_Pop function, void* userdata);
|
||||
|
||||
class SquirrelMessage
|
||||
{
|
||||
public:
|
||||
std::string functionName;
|
||||
FunctionVector args;
|
||||
bool isExternal = false;
|
||||
void* userdata = NULL;
|
||||
SquirrelMessage_External_Pop externalFunc = NULL;
|
||||
};
|
||||
|
||||
class SquirrelMessageBuffer
|
||||
|
@ -243,6 +236,3 @@ typedef SQRESULT (*sq_pushnewstructinstanceType)(HSquirrelVM* sqvm, int fieldCou
|
|||
typedef SQRESULT (*sq_sealstructslotType)(HSquirrelVM* sqvm, int slotIndex);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
// These "external" versions of the types are for plugins
|
||||
typedef int64_t (*RegisterSquirrelFuncType_External)(ScriptContext context, SQFuncRegistration* funcReg, char unknown);
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
#include "shared/misccommands.h"
|
||||
#include "engine/r2engine.h"
|
||||
|
||||
#include "plugins/pluginbackend.h"
|
||||
#include "plugins/plugin_abi.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -152,7 +149,4 @@ ON_DLL_LOAD("engine.dll", ConCommand, (CModule module))
|
|||
{
|
||||
ConCommandConstructor = module.Offset(0x415F60).RCast<ConCommandConstructorType>();
|
||||
AddMiscConCommands();
|
||||
|
||||
g_pPluginCommunicationhandler->m_sEngineData.ConCommandConstructor =
|
||||
reinterpret_cast<PluginConCommandConstructorType>(ConCommandConstructor);
|
||||
}
|
||||
|
|
|
@ -3,9 +3,6 @@
|
|||
#include "convar.h"
|
||||
#include "core/sourceinterface.h"
|
||||
|
||||
#include "plugins/pluginbackend.h"
|
||||
#include "plugins/plugin_abi.h"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
typedef void (*ConVarRegisterType)(
|
||||
|
@ -40,12 +37,6 @@ ON_DLL_LOAD("engine.dll", ConVar, (CModule module))
|
|||
|
||||
g_pCVarInterface = new SourceInterface<CCvar>("vstdlib.dll", "VEngineCvar007");
|
||||
g_pCVar = *g_pCVarInterface;
|
||||
|
||||
g_pPluginCommunicationhandler->m_sEngineData.conVarMalloc = reinterpret_cast<PluginConVarMallocType>(conVarMalloc);
|
||||
g_pPluginCommunicationhandler->m_sEngineData.conVarRegister = reinterpret_cast<PluginConVarRegisterType>(conVarRegister);
|
||||
g_pPluginCommunicationhandler->m_sEngineData.ConVar_Vtable = reinterpret_cast<void*>(g_pConVar_Vtable);
|
||||
g_pPluginCommunicationhandler->m_sEngineData.IConVar_Vtable = reinterpret_cast<void*>(g_pIConVar_Vtable);
|
||||
g_pPluginCommunicationhandler->m_sEngineData.g_pCVar = reinterpret_cast<void*>(g_pCVar);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
};
|
|
@ -2,22 +2,24 @@
|
|||
|
||||
void RemoveAsciiControlSequences(char* str, bool allow_color_codes);
|
||||
|
||||
class ScopeGuard
|
||||
template <typename T> class ScopeGuard
|
||||
{
|
||||
public:
|
||||
auto operator=(ScopeGuard&) = delete;
|
||||
ScopeGuard(ScopeGuard&) = delete;
|
||||
|
||||
ScopeGuard(std::function<void()> callback) : m_callback(callback) {}
|
||||
ScopeGuard(T callback) : m_callback(callback) {}
|
||||
~ScopeGuard()
|
||||
{
|
||||
m_callback();
|
||||
if (!m_dismissed)
|
||||
m_callback();
|
||||
}
|
||||
void Dismiss()
|
||||
{
|
||||
m_callback = [] {};
|
||||
m_dismissed = true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void()> m_callback;
|
||||
bool m_dismissed = false;
|
||||
T m_callback;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue