aboutsummaryrefslogtreecommitdiff
path: root/primedev
diff options
context:
space:
mode:
authorGeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com>2024-08-25 19:18:42 +0200
committerGitHub <noreply@github.com>2024-08-25 19:18:42 +0200
commit5472a3630762db2d6880a4dafda9402dbbc872f8 (patch)
treea8602200e2f5052c6a7ccc9e75e03a428d2c7936 /primedev
parentfff09b8b6805f66c87da2ac39ef5509bffb129cf (diff)
parent5aae42126a062f1d184aff1c8217ef50259ccc53 (diff)
downloadNorthstarLauncher-5472a3630762db2d6880a4dafda9402dbbc872f8.tar.gz
NorthstarLauncher-5472a3630762db2d6880a4dafda9402dbbc872f8.zip
Merge branch 'main' into feat/overhaul-mod-loading-locations
Diffstat (limited to 'primedev')
-rw-r--r--primedev/Northstar.cmake3
-rw-r--r--primedev/client/debugoverlay.cpp25
-rw-r--r--primedev/core/hooks.cpp85
-rw-r--r--primedev/core/hooks.h33
-rw-r--r--primedev/core/math/bitbuf.h115
-rw-r--r--primedev/core/math/color.h80
-rw-r--r--primedev/core/math/vector.h20
-rw-r--r--primedev/core/memalloc.h5
-rw-r--r--primedev/core/sourceinterface.h10
-rw-r--r--primedev/core/vanilla.h5
-rw-r--r--primedev/dllmain.cpp8
-rw-r--r--primedev/engine/gl_matsysiface.cpp50
-rw-r--r--primedev/logging/crashhandler.h40
-rw-r--r--primedev/materialsystem/cmaterialglue.h47
-rw-r--r--primedev/materialsystem/cshaderglue.h7
-rw-r--r--primedev/mods/modmanager.cpp26
-rw-r--r--primedev/scripts/scripthttprequesthandler.h5
-rw-r--r--primedev/server/ai_navmesh.h20
-rw-r--r--primedev/squirrel/squirrel.h125
-rw-r--r--primedev/util/utils.h5
-rw-r--r--primedev/windows/libsys.cpp135
-rw-r--r--primedev/windows/libsys.h3
22 files changed, 395 insertions, 457 deletions
diff --git a/primedev/Northstar.cmake b/primedev/Northstar.cmake
index 40583d28..b8038073 100644
--- a/primedev/Northstar.cmake
+++ b/primedev/Northstar.cmake
@@ -62,6 +62,7 @@ add_library(
"dedicated/dedicatedlogtoclient.cpp"
"dedicated/dedicatedlogtoclient.h"
"dedicated/dedicatedmaterialsystem.cpp"
+ "engine/gl_matsysiface.cpp"
"engine/host.cpp"
"engine/hoststate.cpp"
"engine/hoststate.h"
@@ -161,6 +162,8 @@ add_library(
"util/version.h"
"util/wininfo.cpp"
"util/wininfo.h"
+ "windows/libsys.cpp"
+ "windows/libsys.h"
"dllmain.cpp"
"ns_version.h"
"Northstar.def"
diff --git a/primedev/client/debugoverlay.cpp b/primedev/client/debugoverlay.cpp
index a67b8355..7f2e0901 100644
--- a/primedev/client/debugoverlay.cpp
+++ b/primedev/client/debugoverlay.cpp
@@ -41,10 +41,7 @@ struct OverlayBase_t
struct OverlayLine_t : public OverlayBase_t
{
- OverlayLine_t()
- {
- m_Type = OVERLAY_LINE;
- }
+ OverlayLine_t() { m_Type = OVERLAY_LINE; }
Vector3 origin;
Vector3 dest;
@@ -57,10 +54,7 @@ struct OverlayLine_t : public OverlayBase_t
struct OverlayBox_t : public OverlayBase_t
{
- OverlayBox_t()
- {
- m_Type = OVERLAY_BOX;
- }
+ OverlayBox_t() { m_Type = OVERLAY_BOX; }
Vector3 origin;
Vector3 mins;
@@ -74,10 +68,7 @@ struct OverlayBox_t : public OverlayBase_t
struct OverlayTriangle_t : public OverlayBase_t
{
- OverlayTriangle_t()
- {
- m_Type = OVERLAY_TRIANGLE;
- }
+ OverlayTriangle_t() { m_Type = OVERLAY_TRIANGLE; }
Vector3 p1;
Vector3 p2;
@@ -91,10 +82,7 @@ struct OverlayTriangle_t : public OverlayBase_t
struct OverlaySweptBox_t : public OverlayBase_t
{
- OverlaySweptBox_t()
- {
- m_Type = OVERLAY_SWEPT_BOX;
- }
+ OverlaySweptBox_t() { m_Type = OVERLAY_SWEPT_BOX; }
Vector3 start;
Vector3 end;
@@ -109,10 +97,7 @@ struct OverlaySweptBox_t : public OverlayBase_t
struct OverlaySphere_t : public OverlayBase_t
{
- OverlaySphere_t()
- {
- m_Type = OVERLAY_SPHERE;
- }
+ OverlaySphere_t() { m_Type = OVERLAY_SPHERE; }
Vector3 vOrigin;
float flRadius;
diff --git a/primedev/core/hooks.cpp b/primedev/core/hooks.cpp
index fef8bbcf..5026f837 100644
--- a/primedev/core/hooks.cpp
+++ b/primedev/core/hooks.cpp
@@ -10,8 +10,6 @@
#include <filesystem>
#include <Psapi.h>
-#define XINPUT1_3_DLL "XInput1_3.dll"
-
namespace fs = std::filesystem;
AUTOHOOK_INIT()
@@ -392,87 +390,12 @@ void CallAllPendingDLLLoadCallbacks()
}
}
-// clang-format off
-AUTOHOOK_ABSOLUTEADDR(_LoadLibraryExA, (LPVOID)LoadLibraryExA,
-HMODULE, WINAPI, (LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags))
-// clang-format on
-{
- HMODULE moduleAddress;
-
- LPCSTR lpLibFileNameEnd = lpLibFileName + strlen(lpLibFileName);
- LPCSTR lpLibName = lpLibFileNameEnd - strlen(XINPUT1_3_DLL);
-
- // replace xinput dll with one that has ASLR
- if (lpLibFileName <= lpLibName && !strncmp(lpLibName, XINPUT1_3_DLL, strlen(XINPUT1_3_DLL) + 1))
- {
- moduleAddress = _LoadLibraryExA("XInput9_1_0.dll", hFile, dwFlags);
-
- if (!moduleAddress)
- {
- MessageBoxA(0, "Could not find XInput9_1_0.dll", "Northstar", MB_ICONERROR);
- exit(EXIT_FAILURE);
-
- return nullptr;
- }
- }
- else
- moduleAddress = _LoadLibraryExA(lpLibFileName, hFile, dwFlags);
-
- if (moduleAddress)
- {
- CallLoadLibraryACallbacks(lpLibFileName, moduleAddress);
- g_pPluginManager->InformDllLoad(moduleAddress, fs::path(lpLibFileName));
- }
-
- return moduleAddress;
-}
-
-// clang-format off
-AUTOHOOK_ABSOLUTEADDR(_LoadLibraryA, (LPVOID)LoadLibraryA,
-HMODULE, WINAPI, (LPCSTR lpLibFileName))
-// clang-format on
-{
- HMODULE moduleAddress = _LoadLibraryA(lpLibFileName);
-
- if (moduleAddress)
- CallLoadLibraryACallbacks(lpLibFileName, moduleAddress);
-
- return moduleAddress;
-}
-
-// clang-format off
-AUTOHOOK_ABSOLUTEADDR(_LoadLibraryExW, (LPVOID)LoadLibraryExW,
-HMODULE, WINAPI, (LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags))
-// clang-format on
-{
- HMODULE moduleAddress = _LoadLibraryExW(lpLibFileName, hFile, dwFlags);
-
- if (moduleAddress)
- CallLoadLibraryWCallbacks(lpLibFileName, moduleAddress);
-
- return moduleAddress;
-}
-
-// clang-format off
-AUTOHOOK_ABSOLUTEADDR(_LoadLibraryW, (LPVOID)LoadLibraryW,
-HMODULE, WINAPI, (LPCWSTR lpLibFileName))
-// clang-format on
-{
- HMODULE moduleAddress = _LoadLibraryW(lpLibFileName);
-
- if (moduleAddress)
- {
- CallLoadLibraryWCallbacks(lpLibFileName, moduleAddress);
- g_pPluginManager->InformDllLoad(moduleAddress, fs::path(lpLibFileName));
- }
-
- return moduleAddress;
-}
-
-void InstallInitialHooks()
+void HookSys_Init()
{
if (MH_Initialize() != MH_OK)
+ {
spdlog::error("MH_Initialize (minhook initialization) failed");
-
+ }
+ // todo: remove remaining instances of autohook in this file
AUTOHOOK_DISPATCH()
}
diff --git a/primedev/core/hooks.h b/primedev/core/hooks.h
index e5a65354..2a2180da 100644
--- a/primedev/core/hooks.h
+++ b/primedev/core/hooks.h
@@ -3,7 +3,33 @@
#include <string>
#include <iostream>
-void InstallInitialHooks();
+//-----------------------------------------------------------------------------
+// Purpose: Init minhook
+//-----------------------------------------------------------------------------
+void HookSys_Init();
+
+//-----------------------------------------------------------------------------
+// Purpose: MH_MakeHook wrapper
+// Input : *ppOriginal - Original function being detoured
+// pDetour - Detour function
+//-----------------------------------------------------------------------------
+inline void HookAttach(PVOID* ppOriginal, PVOID pDetour)
+{
+ PVOID pAddr = *ppOriginal;
+ if (MH_CreateHook(pAddr, pDetour, ppOriginal) == MH_OK)
+ {
+ if (MH_EnableHook(pAddr) != MH_OK)
+ {
+ spdlog::error("Failed enabling a function hook!");
+ }
+ }
+ else
+ {
+ spdlog::error("Failed creating a function hook!");
+ }
+}
+
+void CallLoadLibraryACallbacks(LPCSTR lpLibFileName, HMODULE moduleAddress);
typedef void (*DllLoadCallbackFuncType)(CModule moduleAddress);
void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback, std::string tag = "", std::vector<std::string> reliesOn = {});
@@ -301,10 +327,7 @@ public:
pAutohook->vars.push_back(this);
}
- void Dispatch()
- {
- *m_pTarget = (void*)ParseDLLOffsetString(m_pAddrString);
- }
+ void Dispatch() { *m_pTarget = (void*)ParseDLLOffsetString(m_pAddrString); }
};
// VAR_AT(engine.dll+0x404, ConVar*, Cvar_host_timescale)
diff --git a/primedev/core/math/bitbuf.h b/primedev/core/math/bitbuf.h
index a06dab17..33056e63 100644
--- a/primedev/core/math/bitbuf.h
+++ b/primedev/core/math/bitbuf.h
@@ -90,25 +90,13 @@ enum EBitCoordType
class BitBufferBase
{
protected:
- INLINE void SetName(const char* name)
- {
- m_BufferName = name;
- }
+ INLINE void SetName(const char* name) { m_BufferName = name; }
public:
- INLINE bool IsOverflowed()
- {
- return m_Overflow;
- }
- INLINE void SetOverflowed()
- {
- m_Overflow = true;
- }
+ INLINE bool IsOverflowed() { return m_Overflow; }
+ INLINE void SetOverflowed() { m_Overflow = true; }
- INLINE const char* GetName()
- {
- return m_BufferName;
- }
+ INLINE const char* GetName() { return m_BufferName; }
private:
const char* m_BufferName = "";
@@ -437,28 +425,13 @@ public:
return fReturn;
}
- INLINE i32 ReadChar()
- {
- return ReadSBitLong(sizeof(char) << 3);
- }
- INLINE u32 ReadByte()
- {
- return ReadUBitLong(sizeof(unsigned char) << 3);
- }
+ INLINE i32 ReadChar() { return ReadSBitLong(sizeof(char) << 3); }
+ INLINE u32 ReadByte() { return ReadUBitLong(sizeof(unsigned char) << 3); }
- INLINE i32 ReadShort()
- {
- return ReadSBitLong(sizeof(short) << 3);
- }
- INLINE u32 ReadWord()
- {
- return ReadUBitLong(sizeof(unsigned short) << 3);
- }
+ INLINE i32 ReadShort() { return ReadSBitLong(sizeof(short) << 3); }
+ INLINE u32 ReadWord() { return ReadUBitLong(sizeof(unsigned short) << 3); }
- INLINE i32 ReadLong()
- {
- return (i32)(ReadUBitLong(sizeof(i32) << 3));
- }
+ INLINE i32 ReadLong() { return (i32)(ReadUBitLong(sizeof(i32) << 3)); }
INLINE float ReadFloat()
{
u32 temp = ReadUBitLong(sizeof(float) << 3);
@@ -687,24 +660,12 @@ public:
return std::min(nCurOfs + nAdjust, m_DataBits);
}
- INLINE bool SeekRelative(size_t offset)
- {
- return Seek(GetNumBitsRead() + offset);
- }
+ INLINE bool SeekRelative(size_t offset) { return Seek(GetNumBitsRead() + offset); }
- INLINE size_t TotalBytesAvailable()
- {
- return m_DataBytes;
- }
+ INLINE size_t TotalBytesAvailable() { return m_DataBytes; }
- INLINE size_t GetNumBitsLeft()
- {
- return m_DataBits - GetNumBitsRead();
- }
- INLINE size_t GetNumBytesLeft()
- {
- return GetNumBitsLeft() >> 3;
- }
+ INLINE size_t GetNumBitsLeft() { return m_DataBits - GetNumBitsRead(); }
+ INLINE size_t GetNumBytesLeft() { return GetNumBitsLeft() >> 3; }
private:
size_t m_DataBits; // 0x0010
@@ -743,10 +704,7 @@ public:
m_DataEnd = reinterpret_cast<u32*>(reinterpret_cast<u8*>(m_Data) + m_DataBytes);
}
- INLINE int GetNumBitsLeft()
- {
- return m_OutBitsLeft + (32 * (m_DataEnd - m_DataOut - 1));
- }
+ INLINE int GetNumBitsLeft() { return m_OutBitsLeft + (32 * (m_DataEnd - m_DataOut - 1)); }
INLINE void Reset()
{
@@ -775,10 +733,7 @@ public:
return reinterpret_cast<u8*>(m_Data);
}
- INLINE u8* GetData()
- {
- return GetBasePointer();
- }
+ INLINE u8* GetData() { return GetBasePointer(); }
INLINE void Finish()
{
@@ -851,10 +806,7 @@ public:
}
}
- INLINE void WriteSBitLong(i32 data, i32 numBits)
- {
- WriteUBitLong((u32)data, numBits, false);
- }
+ INLINE void WriteSBitLong(i32 data, i32 numBits) { WriteUBitLong((u32)data, numBits, false); }
INLINE void WriteUBitVar(u32 n)
{
@@ -911,40 +863,19 @@ public:
return !IsOverflowed();
}
- INLINE bool WriteBytes(const uptr data, i32 numBytes)
- {
- return WriteBits(data, numBytes << 3);
- }
+ INLINE bool WriteBytes(const uptr data, i32 numBytes) { return WriteBits(data, numBytes << 3); }
- INLINE i32 GetNumBitsWritten()
- {
- return (32 - m_OutBitsLeft) + (32 * (m_DataOut - m_Data));
- }
+ INLINE i32 GetNumBitsWritten() { return (32 - m_OutBitsLeft) + (32 * (m_DataOut - m_Data)); }
- INLINE i32 GetNumBytesWritten()
- {
- return (GetNumBitsWritten() + 7) >> 3;
- }
+ INLINE i32 GetNumBytesWritten() { return (GetNumBitsWritten() + 7) >> 3; }
- INLINE void WriteChar(i32 val)
- {
- WriteSBitLong(val, sizeof(char) << 3);
- }
+ INLINE void WriteChar(i32 val) { WriteSBitLong(val, sizeof(char) << 3); }
- INLINE void WriteByte(i32 val)
- {
- WriteUBitLong(val, sizeof(unsigned char) << 3, false);
- }
+ INLINE void WriteByte(i32 val) { WriteUBitLong(val, sizeof(unsigned char) << 3, false); }
- INLINE void WriteShort(i32 val)
- {
- WriteSBitLong(val, sizeof(short) << 3);
- }
+ INLINE void WriteShort(i32 val) { WriteSBitLong(val, sizeof(short) << 3); }
- INLINE void WriteWord(i32 val)
- {
- WriteUBitLong(val, sizeof(unsigned short) << 3);
- }
+ INLINE void WriteWord(i32 val) { WriteUBitLong(val, sizeof(unsigned short) << 3); }
INLINE bool WriteString(const char* str)
{
diff --git a/primedev/core/math/color.h b/primedev/core/math/color.h
index 013c4e4c..a46bc089 100644
--- a/primedev/core/math/color.h
+++ b/primedev/core/math/color.h
@@ -7,22 +7,10 @@ struct color24
typedef struct color32_s
{
- bool operator!=(const struct color32_s& other) const
- {
- return r != other.r || g != other.g || b != other.b || a != other.a;
- }
- inline unsigned* asInt(void)
- {
- return reinterpret_cast<unsigned*>(this);
- }
- inline const unsigned* asInt(void) const
- {
- return reinterpret_cast<const unsigned*>(this);
- }
- inline void Copy(const color32_s& rhs)
- {
- *asInt() = *rhs.asInt();
- }
+ bool operator!=(const struct color32_s& other) const { return r != other.r || g != other.g || b != other.b || a != other.a; }
+ inline unsigned* asInt(void) { return reinterpret_cast<unsigned*>(this); }
+ inline const unsigned* asInt(void) const { return reinterpret_cast<const unsigned*>(this); }
+ inline void Copy(const color32_s& rhs) { *asInt() = *rhs.asInt(); }
uint8_t r, g, b, a;
} color32;
@@ -79,55 +67,22 @@ public:
_b = _color[2];
_a = _color[3];
}
- int GetValue(int index) const
- {
- return _color[index];
- }
- void SetRawColor(int color32)
- {
- *((int*)this) = color32;
- }
- int GetRawColor(void) const
- {
- return *((int*)this);
- }
+ int GetValue(int index) const { return _color[index]; }
+ void SetRawColor(int color32) { *((int*)this) = color32; }
+ int GetRawColor(void) const { return *((int*)this); }
- inline int r() const
- {
- return _color[0];
- }
- inline int g() const
- {
- return _color[1];
- }
- inline int b() const
- {
- return _color[2];
- }
- inline int a() const
- {
- return _color[3];
- }
+ inline int r() const { return _color[0]; }
+ inline int g() const { return _color[1]; }
+ inline int b() const { return _color[2]; }
+ inline int a() const { return _color[3]; }
- unsigned char& operator[](int index)
- {
- return _color[index];
- }
+ unsigned char& operator[](int index) { return _color[index]; }
- const unsigned char& operator[](int index) const
- {
- return _color[index];
- }
+ const unsigned char& operator[](int index) const { return _color[index]; }
- bool operator==(const Color& rhs) const
- {
- return (*((int*)this) == *((int*)&rhs));
- }
+ bool operator==(const Color& rhs) const { return (*((int*)this) == *((int*)&rhs)); }
- bool operator!=(const Color& rhs) const
- {
- return !(operator==(rhs));
- }
+ bool operator!=(const Color& rhs) const { return !(operator==(rhs)); }
Color& operator=(const Color& rhs)
{
@@ -164,10 +119,7 @@ public:
return out;
}
- SourceColor ToSourceColor()
- {
- return SourceColor(_color[0], _color[1], _color[2], _color[3]);
- }
+ SourceColor ToSourceColor() { return SourceColor(_color[0], _color[1], _color[2], _color[3]); }
private:
unsigned char _color[4];
diff --git a/primedev/core/math/vector.h b/primedev/core/math/vector.h
index e62f2c93..0face732 100644
--- a/primedev/core/math/vector.h
+++ b/primedev/core/math/vector.h
@@ -17,10 +17,7 @@ public:
Vector3(float _f) : x(_f), y(_f), z(_f) {}
Vector3() : x(0.0f), y(0.0f), z(0.0f) {}
- inline bool IsValid()
- {
- return IsFinite(x) && IsFinite(y) && IsFinite(z);
- }
+ inline bool IsValid() { return IsFinite(x) && IsFinite(y) && IsFinite(z); }
inline void Init(float fX = 0.0f, float fY = 0.0f, float fZ = 0.0f)
{
@@ -29,10 +26,7 @@ public:
z = fZ;
}
- inline float Length()
- {
- return FastSqrt(x * x + y * y + z * z);
- }
+ inline float Length() { return FastSqrt(x * x + y * y + z * z); }
inline float DistTo(const Vector3& vOther)
{
@@ -44,10 +38,7 @@ public:
return vDelta.Length();
}
- float Dot(const Vector3& vOther) const
- {
- return x * vOther.x + y * vOther.y + z * vOther.z;
- }
+ 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;
@@ -318,10 +309,7 @@ public:
Vector3 GetNormal() const;
// todo: more operators maybe
- bool operator==(const QAngle& other)
- {
- return x == other.x && y == other.y && z == other.z;
- }
+ bool operator==(const QAngle& other) { return x == other.x && y == other.y && z == other.z; }
};
inline Vector3 QAngle::GetNormal() const
diff --git a/primedev/core/memalloc.h b/primedev/core/memalloc.h
index 73e078f5..a55ce361 100644
--- a/primedev/core/memalloc.h
+++ b/primedev/core/memalloc.h
@@ -40,10 +40,7 @@ public:
}
return _realloc_base(originalPtr, newSize);
}
- static void Free(void* ptr)
- {
- _free_base(ptr);
- }
+ static void Free(void* ptr) { _free_base(ptr); }
};
typedef rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::MemoryPoolAllocator<SourceAllocator>, SourceAllocator> rapidjson_document;
diff --git a/primedev/core/sourceinterface.h b/primedev/core/sourceinterface.h
index bbbbd3bc..730339da 100644
--- a/primedev/core/sourceinterface.h
+++ b/primedev/core/sourceinterface.h
@@ -26,13 +26,7 @@ public:
spdlog::error("Failed to call CreateInterface for %s in %s", interfaceName, moduleName);
}
- T* operator->() const
- {
- return m_interface;
- }
+ T* operator->() const { return m_interface; }
- operator T*() const
- {
- return m_interface;
- }
+ operator T*() const { return m_interface; }
};
diff --git a/primedev/core/vanilla.h b/primedev/core/vanilla.h
index b0797803..356495c8 100644
--- a/primedev/core/vanilla.h
+++ b/primedev/core/vanilla.h
@@ -17,10 +17,7 @@ public:
m_bIsVanillaCompatible = isVanilla;
}
- bool GetVanillaCompatibility()
- {
- return m_bIsVanillaCompatible;
- }
+ bool GetVanillaCompatibility() { return m_bIsVanillaCompatible; }
private:
bool m_bIsVanillaCompatible = false;
diff --git a/primedev/dllmain.cpp b/primedev/dllmain.cpp
index 1191307f..95ea103f 100644
--- a/primedev/dllmain.cpp
+++ b/primedev/dllmain.cpp
@@ -10,6 +10,8 @@
#include "squirrel/squirrel.h"
#include "server/serverpresence.h"
+#include "windows/libsys.h"
+
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
@@ -64,7 +66,11 @@ bool InitialiseNorthstar()
// Write launcher version to log
StartupLog();
- InstallInitialHooks();
+ // Init minhook
+ HookSys_Init();
+
+ // Init loadlibrary callbacks
+ LibSys_Init();
g_pServerPresence = new ServerPresenceManager();
diff --git a/primedev/engine/gl_matsysiface.cpp b/primedev/engine/gl_matsysiface.cpp
new file mode 100644
index 00000000..903a0113
--- /dev/null
+++ b/primedev/engine/gl_matsysiface.cpp
@@ -0,0 +1,50 @@
+#include "materialsystem/cmaterialglue.h"
+
+CMaterialGlue* (*GetMaterialAtCrossHair)();
+
+AUTOHOOK_INIT()
+
+AUTOHOOK(CC_mat_crosshair_printmaterial_f, engine.dll + 0xB3C40, void, __fastcall, (const CCommand& args))
+{
+ CMaterialGlue* pMat = GetMaterialAtCrossHair();
+
+ if (!pMat)
+ {
+ spdlog::error("Not looking at a material!");
+ return;
+ }
+
+ std::function<void(CMaterialGlue * pGlue, const char* szName)> fnPrintGlue = [](CMaterialGlue* pGlue, const char* szName)
+ {
+ spdlog::info("|-----------------------------------------------");
+
+ if (!pGlue)
+ {
+ spdlog::info("|-- {} is NULL", szName);
+ return;
+ }
+
+ spdlog::info("|-- Name: {}", szName);
+ spdlog::info("|-- GUID: {:#x}", pGlue->m_GUID);
+ spdlog::info("|-- Name: {}", pGlue->m_pszName);
+ spdlog::info("|-- Width : {}", pGlue->m_iWidth);
+ spdlog::info("|-- Height: {}", pGlue->m_iHeight);
+ };
+
+ spdlog::info("|- GUID: {:#x}", pMat->m_GUID);
+ spdlog::info("|- Name: {}", pMat->m_pszName);
+ spdlog::info("|- Width : {}", pMat->m_iWidth);
+ spdlog::info("|- Height: {}", pMat->m_iHeight);
+
+ fnPrintGlue(pMat->m_pDepthShadow, "DepthShadow");
+ fnPrintGlue(pMat->m_pDepthPrepass, "DepthPrepass");
+ fnPrintGlue(pMat->m_pDepthVSM, "DepthVSM");
+ fnPrintGlue(pMat->m_pColPass, "ColPass");
+}
+
+ON_DLL_LOAD("engine.dll", GlMatSysIFace, (CModule module))
+{
+ AUTOHOOK_DISPATCH()
+
+ GetMaterialAtCrossHair = module.Offset(0xB37D0).RCast<CMaterialGlue* (*)()>();
+}
diff --git a/primedev/logging/crashhandler.h b/primedev/logging/crashhandler.h
index c059a8ca..992dd7d2 100644
--- a/primedev/logging/crashhandler.h
+++ b/primedev/logging/crashhandler.h
@@ -14,35 +14,17 @@ public:
void Init();
void Shutdown();
- void Lock()
- {
- m_Mutex.lock();
- }
-
- void Unlock()
- {
- m_Mutex.unlock();
- }
-
- void SetState(bool bState)
- {
- m_bState = bState;
- }
-
- bool GetState() const
- {
- return m_bState;
- }
-
- void SetAllFatal(bool bState)
- {
- m_bAllExceptionsFatal = bState;
- }
-
- bool GetAllFatal() const
- {
- return m_bAllExceptionsFatal;
- }
+ void Lock() { m_Mutex.lock(); }
+
+ void Unlock() { m_Mutex.unlock(); }
+
+ void SetState(bool bState) { m_bState = bState; }
+
+ bool GetState() const { return m_bState; }
+
+ void SetAllFatal(bool bState) { m_bAllExceptionsFatal = bState; }
+
+ bool GetAllFatal() const { return m_bAllExceptionsFatal; }
//-----------------------------------------------------------------------------
// Exception helpers
diff --git a/primedev/materialsystem/cmaterialglue.h b/primedev/materialsystem/cmaterialglue.h
new file mode 100644
index 00000000..1738a91a
--- /dev/null
+++ b/primedev/materialsystem/cmaterialglue.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "materialsystem/cshaderglue.h"
+
+class CMaterialGlue
+{
+public:
+ void* m_pVFTable;
+ char m_unk[8];
+
+ uint64_t m_GUID;
+
+ const char* m_pszName;
+ const char* m_pszSurfaceProp;
+ const char* m_pszSurfaceProp2;
+
+ CMaterialGlue* m_pDepthShadow;
+ CMaterialGlue* m_pDepthPrepass;
+ CMaterialGlue* m_pDepthVSM;
+ CMaterialGlue* m_pColPass;
+
+ char gap_50[64];
+
+ CShaderGlue* m_pShaderGlue;
+ void** m_pTextureHandles;
+ void** m_pStreamingTextures;
+ int16_t m_iStreamingTextureCount;
+ uint8_t m_iSamplersIndices[4];
+ int16_t m_iUnknown0;
+ char gap_B0[12];
+
+ int16_t aword_BC[2];
+ int32_t flags2;
+ int32_t flags3;
+ int16_t m_iWidth;
+ int16_t m_iHeight;
+ int16_t m_iUnknown1;
+ int16_t m_iUnknown2;
+
+ void** m_pUnkD3D11Ptr;
+ void* m_pD3D11Buffer;
+ void* qword_E0;
+ void* pointer_E8;
+
+ int32_t dword_F0;
+ char gap_F4[12];
+};
diff --git a/primedev/materialsystem/cshaderglue.h b/primedev/materialsystem/cshaderglue.h
new file mode 100644
index 00000000..8194f1fb
--- /dev/null
+++ b/primedev/materialsystem/cshaderglue.h
@@ -0,0 +1,7 @@
+#pragma once
+
+class CShaderGlue
+{
+public:
+ void* vftable;
+};
diff --git a/primedev/mods/modmanager.cpp b/primedev/mods/modmanager.cpp
index b3c8ab7a..cc6195c7 100644
--- a/primedev/mods/modmanager.cpp
+++ b/primedev/mods/modmanager.cpp
@@ -883,16 +883,24 @@ void ModManager::LoadMods()
if (fs::is_regular_file(file) && file.path().extension() == ".rpak")
{
std::string pakName(file.path().filename().string());
-
ModRpakEntry& modPak = mod.Rpaks.emplace_back();
- modPak.m_bAutoLoad =
- !bUseRpakJson || (dRpakJson.HasMember("Preload") && dRpakJson["Preload"].IsObject() &&
- dRpakJson["Preload"].HasMember(pakName) && dRpakJson["Preload"][pakName].IsTrue());
-
- // postload things
- if (!bUseRpakJson ||
- (dRpakJson.HasMember("Postload") && dRpakJson["Postload"].IsObject() && dRpakJson["Postload"].HasMember(pakName)))
- modPak.m_sLoadAfterPak = dRpakJson["Postload"][pakName].GetString();
+
+ if (!bUseRpakJson)
+ {
+ spdlog::warn("Mod {} contains rpaks without valid rpak.json, rpaks might not be loaded", mod.Name);
+ }
+ else
+ {
+ modPak.m_bAutoLoad =
+ (dRpakJson.HasMember("Preload") && dRpakJson["Preload"].IsObject() && dRpakJson["Preload"].HasMember(pakName) &&
+ dRpakJson["Preload"][pakName].IsTrue());
+
+ // postload things
+ if (dRpakJson.HasMember("Postload") && dRpakJson["Postload"].IsObject() && dRpakJson["Postload"].HasMember(pakName))
+ {
+ modPak.m_sLoadAfterPak = dRpakJson["Postload"][pakName].GetString();
+ }
+ }
modPak.m_sPakName = pakName;
diff --git a/primedev/scripts/scripthttprequesthandler.h b/primedev/scripts/scripthttprequesthandler.h
index f3921f4e..72f719ec 100644
--- a/primedev/scripts/scripthttprequesthandler.h
+++ b/primedev/scripts/scripthttprequesthandler.h
@@ -107,10 +107,7 @@ public:
void StopHttpRequestHandler();
// Whether or not this http request handler is currently running.
- bool IsRunning() const
- {
- return m_bIsHttpRequestHandlerRunning;
- }
+ bool IsRunning() const { return m_bIsHttpRequestHandlerRunning; }
/**
* Creates a new thread to execute an HTTP request.
diff --git a/primedev/server/ai_navmesh.h b/primedev/server/ai_navmesh.h
index 65529f7a..c3339110 100644
--- a/primedev/server/ai_navmesh.h
+++ b/primedev/server/ai_navmesh.h
@@ -207,28 +207,16 @@ struct dtPoly
Vector3 org; //
/// Sets the user defined area id. [Limit: < #DT_MAX_AREAS]
- inline void setArea(unsigned char a)
- {
- areaAndtype = (areaAndtype & 0xc0) | (a & 0x3f);
- }
+ 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);
- }
+ 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;
- }
+ inline unsigned char getArea() const { return areaAndtype & 0x3f; }
/// Gets the polygon type. (See: #dtPolyTypes)
- inline unsigned char getType() const
- {
- return areaAndtype >> 6;
- }
+ inline unsigned char getType() const { return areaAndtype >> 6; }
};
/// Defines a link between polygons.
diff --git a/primedev/squirrel/squirrel.h b/primedev/squirrel/squirrel.h
index 547b1efc..086ab9c6 100644
--- a/primedev/squirrel/squirrel.h
+++ b/primedev/squirrel/squirrel.h
@@ -126,10 +126,7 @@ public:
#pragma endregion
#pragma region SQVM func wrappers
- inline void defconst(CSquirrelVM* sqvm, const SQChar* pName, int nValue)
- {
- __sq_defconst(sqvm, pName, nValue);
- }
+ inline void defconst(CSquirrelVM* sqvm, const SQChar* pName, int nValue) { __sq_defconst(sqvm, pName, nValue); }
inline SQRESULT
compilebuffer(CompileBufferState* bufferState, const SQChar* bufferName = "unnamedbuffer", const SQBool bShouldThrowError = false)
@@ -137,110 +134,50 @@ public:
return __sq_compilebuffer(m_pSQVM->sqvm, bufferState, bufferName, -1, bShouldThrowError);
}
- inline SQRESULT _call(HSquirrelVM* sqvm, const SQInteger args)
- {
- return __sq_call(sqvm, args + 1, false, true);
- }
+ inline SQRESULT _call(HSquirrelVM* sqvm, const SQInteger args) { return __sq_call(sqvm, args + 1, false, true); }
- inline SQInteger raiseerror(HSquirrelVM* sqvm, const SQChar* sError)
- {
- return __sq_raiseerror(sqvm, sError);
- }
+ inline SQInteger raiseerror(HSquirrelVM* sqvm, const SQChar* sError) { return __sq_raiseerror(sqvm, sError); }
inline bool compilefile(CSquirrelVM* sqvm, const char* path, const char* name, int a4)
{
return __sq_compilefile(sqvm, path, name, a4);
}
- inline void newarray(HSquirrelVM* sqvm, const SQInteger stackpos = 0)
- {
- __sq_newarray(sqvm, stackpos);
- }
+ inline void newarray(HSquirrelVM* sqvm, const SQInteger stackpos = 0) { __sq_newarray(sqvm, stackpos); }
- inline SQRESULT arrayappend(HSquirrelVM* sqvm, const SQInteger stackpos)
- {
- return __sq_arrayappend(sqvm, stackpos);
- }
+ inline SQRESULT arrayappend(HSquirrelVM* sqvm, const SQInteger stackpos) { return __sq_arrayappend(sqvm, stackpos); }
- inline SQRESULT newtable(HSquirrelVM* sqvm)
- {
- return __sq_newtable(sqvm);
- }
+ inline SQRESULT newtable(HSquirrelVM* sqvm) { return __sq_newtable(sqvm); }
- inline SQRESULT newslot(HSquirrelVM* sqvm, SQInteger idx, SQBool bStatic)
- {
- return __sq_newslot(sqvm, idx, bStatic);
- }
+ inline SQRESULT newslot(HSquirrelVM* sqvm, SQInteger idx, SQBool bStatic) { return __sq_newslot(sqvm, idx, bStatic); }
- inline void pushroottable(HSquirrelVM* sqvm)
- {
- __sq_pushroottable(sqvm);
- }
+ inline void pushroottable(HSquirrelVM* sqvm) { __sq_pushroottable(sqvm); }
- inline void pushstring(HSquirrelVM* sqvm, const SQChar* sVal, int length = -1)
- {
- __sq_pushstring(sqvm, sVal, length);
- }
+ inline void pushstring(HSquirrelVM* sqvm, const SQChar* sVal, int length = -1) { __sq_pushstring(sqvm, sVal, length); }
- inline void pushinteger(HSquirrelVM* sqvm, const SQInteger iVal)
- {
- __sq_pushinteger(sqvm, iVal);
- }
+ inline void pushinteger(HSquirrelVM* sqvm, const SQInteger iVal) { __sq_pushinteger(sqvm, iVal); }
- inline void pushfloat(HSquirrelVM* sqvm, const SQFloat flVal)
- {
- __sq_pushfloat(sqvm, flVal);
- }
+ inline void pushfloat(HSquirrelVM* sqvm, const SQFloat flVal) { __sq_pushfloat(sqvm, flVal); }
- inline void pushbool(HSquirrelVM* sqvm, const SQBool bVal)
- {
- __sq_pushbool(sqvm, bVal);
- }
+ inline void pushbool(HSquirrelVM* sqvm, const SQBool bVal) { __sq_pushbool(sqvm, bVal); }
- inline void pushasset(HSquirrelVM* sqvm, const SQChar* sVal, int length = -1)
- {
- __sq_pushasset(sqvm, sVal, length);
- }
+ inline void pushasset(HSquirrelVM* sqvm, const SQChar* sVal, int length = -1) { __sq_pushasset(sqvm, sVal, length); }
- inline void pushvector(HSquirrelVM* sqvm, const Vector3 pVal)
- {
- __sq_pushvector(sqvm, (float*)&pVal);
- }
+ inline void pushvector(HSquirrelVM* sqvm, const Vector3 pVal) { __sq_pushvector(sqvm, (float*)&pVal); }
- inline void pushobject(HSquirrelVM* sqvm, SQObject* obj)
- {
- __sq_pushobject(sqvm, obj);
- }
+ inline void pushobject(HSquirrelVM* sqvm, SQObject* obj) { __sq_pushobject(sqvm, obj); }
- inline const SQChar* getstring(HSquirrelVM* sqvm, const SQInteger stackpos)
- {
- return __sq_getstring(sqvm, stackpos);
- }
+ inline const SQChar* getstring(HSquirrelVM* sqvm, const SQInteger stackpos) { return __sq_getstring(sqvm, stackpos); }
- inline SQInteger getinteger(HSquirrelVM* sqvm, const SQInteger stackpos)
- {
- return __sq_getinteger(sqvm, stackpos);
- }
+ inline SQInteger getinteger(HSquirrelVM* sqvm, const SQInteger stackpos) { return __sq_getinteger(sqvm, stackpos); }
- inline SQFloat getfloat(HSquirrelVM* sqvm, const SQInteger stackpos)
- {
- return __sq_getfloat(sqvm, stackpos);
- }
+ inline SQFloat getfloat(HSquirrelVM* sqvm, const SQInteger stackpos) { return __sq_getfloat(sqvm, stackpos); }
- inline SQBool getbool(HSquirrelVM* sqvm, const SQInteger stackpos)
- {
- return __sq_getbool(sqvm, stackpos);
- }
+ inline SQBool getbool(HSquirrelVM* sqvm, const SQInteger stackpos) { return __sq_getbool(sqvm, stackpos); }
- inline SQRESULT get(HSquirrelVM* sqvm, const SQInteger stackpos)
- {
- return __sq_get(sqvm, stackpos);
- }
+ inline SQRESULT get(HSquirrelVM* sqvm, const SQInteger stackpos) { return __sq_get(sqvm, stackpos); }
- inline Vector3 getvector(HSquirrelVM* sqvm, const SQInteger stackpos)
- {
- return *(Vector3*)__sq_getvector(sqvm, stackpos);
- }
+ inline Vector3 getvector(HSquirrelVM* sqvm, const SQInteger stackpos) { return *(Vector3*)__sq_getvector(sqvm, stackpos); }
inline int sq_getfunction(HSquirrelVM* sqvm, const char* name, SQObject* returnObj, const char* signature)
{
@@ -291,10 +228,7 @@ public:
return __sq_setuserdatatypeid(sqvm, stackpos, typeId);
}
- template <typename T> inline SQBool getthisentity(HSquirrelVM* sqvm, T* ppEntity)
- {
- return __sq_getthisentity(sqvm, (void**)ppEntity);
- }
+ template <typename T> inline SQBool getthisentity(HSquirrelVM* sqvm, T* ppEntity) { return __sq_getthisentity(sqvm, (void**)ppEntity); }
template <typename T> inline T* getentity(HSquirrelVM* sqvm, SQInteger iStackPos)
{
@@ -305,15 +239,9 @@ public:
return (T*)__sq_getentityfrominstance(m_pSQVM, &obj, __sq_GetEntityConstant_CBaseEntity());
}
- inline SQRESULT pushnewstructinstance(HSquirrelVM* sqvm, const int fieldCount)
- {
- return __sq_pushnewstructinstance(sqvm, fieldCount);
- }
+ inline SQRESULT pushnewstructinstance(HSquirrelVM* sqvm, const int fieldCount) { return __sq_pushnewstructinstance(sqvm, fieldCount); }
- inline SQRESULT sealstructslot(HSquirrelVM* sqvm, const int fieldIndex)
- {
- return __sq_sealstructslot(sqvm, fieldIndex);
- }
+ inline SQRESULT sealstructslot(HSquirrelVM* sqvm, const int fieldIndex) { return __sq_sealstructslot(sqvm, fieldIndex); }
#pragma endregion
};
@@ -405,10 +333,7 @@ public:
#pragma endregion
public:
- SquirrelManager()
- {
- m_pSQVM = nullptr;
- }
+ SquirrelManager() { m_pSQVM = nullptr; }
void VMCreated(CSquirrelVM* newSqvm);
void VMDestroyed();
diff --git a/primedev/util/utils.h b/primedev/util/utils.h
index c8cbc7e8..4b7f57c8 100644
--- a/primedev/util/utils.h
+++ b/primedev/util/utils.h
@@ -14,10 +14,7 @@ public:
if (!m_dismissed)
m_callback();
}
- void Dismiss()
- {
- m_dismissed = true;
- }
+ void Dismiss() { m_dismissed = true; }
private:
bool m_dismissed = false;
diff --git a/primedev/windows/libsys.cpp b/primedev/windows/libsys.cpp
new file mode 100644
index 00000000..501eae68
--- /dev/null
+++ b/primedev/windows/libsys.cpp
@@ -0,0 +1,135 @@
+#include "libsys.h"
+#include "plugins/pluginmanager.h"
+
+#define XINPUT1_3_DLL "XInput1_3.dll"
+
+typedef HMODULE (*WINAPI ILoadLibraryA)(LPCSTR lpLibFileName);
+typedef HMODULE (*WINAPI ILoadLibraryExA)(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
+typedef HMODULE (*WINAPI ILoadLibraryW)(LPCWSTR lpLibFileName);
+typedef HMODULE (*WINAPI ILoadLibraryExW)(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
+
+ILoadLibraryA o_LoadLibraryA = nullptr;
+ILoadLibraryExA o_LoadLibraryExA = nullptr;
+ILoadLibraryW o_LoadLibraryW = nullptr;
+ILoadLibraryExW o_LoadLibraryExW = nullptr;
+
+//-----------------------------------------------------------------------------
+// Purpose: Run detour callbacks for given HMODULE
+//-----------------------------------------------------------------------------
+void LibSys_RunModuleCallbacks(HMODULE hModule)
+{
+ if (!hModule)
+ {
+ return;
+ }
+
+ // Get module base name in ASCII as noone wants to deal with unicode
+ CHAR szModuleName[MAX_PATH];
+ GetModuleBaseNameA(GetCurrentProcess(), hModule, szModuleName, MAX_PATH);
+
+ // DevMsg(eLog::NONE, "%s\n", szModuleName);
+
+ // Call callbacks
+ CallLoadLibraryACallbacks(szModuleName, hModule);
+ g_pPluginManager->InformDllLoad(hModule, fs::path(szModuleName));
+}
+
+//-----------------------------------------------------------------------------
+// Load library callbacks
+
+HMODULE WINAPI WLoadLibraryA(LPCSTR lpLibFileName)
+{
+ HMODULE hModule = o_LoadLibraryA(lpLibFileName);
+
+ LibSys_RunModuleCallbacks(hModule);
+
+ return hModule;
+}
+
+HMODULE WINAPI WLoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
+{
+ HMODULE hModule;
+
+ LPCSTR lpLibFileNameEnd = lpLibFileName + strlen(lpLibFileName);
+ LPCSTR lpLibName = lpLibFileNameEnd - strlen(XINPUT1_3_DLL);
+
+ // replace xinput dll with one that has ASLR
+ if (lpLibFileName <= lpLibName && !strncmp(lpLibName, XINPUT1_3_DLL, strlen(XINPUT1_3_DLL) + 1))
+ {
+ const char* pszReplacementDll = "XInput1_4.dll";
+ hModule = o_LoadLibraryExA(pszReplacementDll, hFile, dwFlags);
+
+ if (!hModule)
+ {
+ pszReplacementDll = "XInput9_1_0.dll";
+ spdlog::warn("Couldn't load XInput1_4.dll. Will try XInput9_1_0.dll. If on Windows 7 this is expected");
+ hModule = o_LoadLibraryExA(pszReplacementDll, hFile, dwFlags);
+ }
+
+ if (!hModule)
+ {
+ spdlog::error("Couldn't load XInput9_1_0.dll");
+ MessageBoxA(
+ 0, "Could not load a replacement for XInput1_3.dll\nTried: XInput1_4.dll and XInput9_1_0.dll", "Northstar", MB_ICONERROR);
+ exit(EXIT_FAILURE);
+
+ return nullptr;
+ }
+
+ spdlog::info("Successfully loaded {} as a replacement for XInput1_3.dll", pszReplacementDll);
+ }
+ else
+ {
+ hModule = o_LoadLibraryExA(lpLibFileName, hFile, dwFlags);
+ }
+
+ bool bShouldRunCallbacks =
+ !(dwFlags & (LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE));
+ if (bShouldRunCallbacks)
+ {
+ LibSys_RunModuleCallbacks(hModule);
+ }
+
+ return hModule;
+}
+
+HMODULE WINAPI WLoadLibraryW(LPCWSTR lpLibFileName)
+{
+ HMODULE hModule = o_LoadLibraryW(lpLibFileName);
+
+ LibSys_RunModuleCallbacks(hModule);
+
+ return hModule;
+}
+
+HMODULE WINAPI WLoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
+{
+ HMODULE hModule = o_LoadLibraryExW(lpLibFileName, hFile, dwFlags);
+
+ bool bShouldRunCallbacks =
+ !(dwFlags & (LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE));
+ if (bShouldRunCallbacks)
+ {
+ LibSys_RunModuleCallbacks(hModule);
+ }
+
+ return hModule;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Initilase dll load callbacks
+//-----------------------------------------------------------------------------
+void LibSys_Init()
+{
+ HMODULE hKernel = GetModuleHandleA("KERNEL32.DLL");
+
+ o_LoadLibraryA = reinterpret_cast<ILoadLibraryA>(GetProcAddress(hKernel, "LoadLibraryA"));
+ o_LoadLibraryExA = reinterpret_cast<ILoadLibraryExA>(GetProcAddress(hKernel, "LoadLibraryExA"));
+ o_LoadLibraryW = reinterpret_cast<ILoadLibraryW>(GetProcAddress(hKernel, "LoadLibraryW"));
+ o_LoadLibraryExW = reinterpret_cast<ILoadLibraryExW>(GetProcAddress(hKernel, "LoadLibraryExW"));
+
+ HookAttach(&(PVOID&)o_LoadLibraryA, (PVOID)WLoadLibraryA);
+ HookAttach(&(PVOID&)o_LoadLibraryExA, (PVOID)WLoadLibraryExA);
+ HookAttach(&(PVOID&)o_LoadLibraryW, (PVOID)WLoadLibraryW);
+ HookAttach(&(PVOID&)o_LoadLibraryExW, (PVOID)WLoadLibraryExW);
+}
diff --git a/primedev/windows/libsys.h b/primedev/windows/libsys.h
new file mode 100644
index 00000000..91345d8f
--- /dev/null
+++ b/primedev/windows/libsys.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void LibSys_Init();