aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDLL
diff options
context:
space:
mode:
Diffstat (limited to 'NorthstarDLL')
-rw-r--r--NorthstarDLL/NorthstarDLL.vcxproj4
-rw-r--r--NorthstarDLL/NorthstarDLL.vcxproj.filters9
-rw-r--r--NorthstarDLL/audio.cpp6
-rw-r--r--NorthstarDLL/bansystem.cpp111
-rw-r--r--NorthstarDLL/chatcommand.cpp2
-rw-r--r--NorthstarDLL/clientvideooverrides.cpp4
-rw-r--r--NorthstarDLL/convar.cpp2
-rw-r--r--NorthstarDLL/debugoverlay.cpp2
-rw-r--r--NorthstarDLL/dllmain.cpp4
-rw-r--r--NorthstarDLL/exploitfixes.cpp90
-rw-r--r--NorthstarDLL/exploitfixes_utf8parser.cpp8
-rw-r--r--NorthstarDLL/filesystem.cpp2
-rw-r--r--NorthstarDLL/hoststate.cpp4
-rw-r--r--NorthstarDLL/latencyflex.cpp21
-rw-r--r--NorthstarDLL/logging.cpp3
-rw-r--r--NorthstarDLL/masterserver.h2
-rw-r--r--NorthstarDLL/maxplayers.cpp6
-rw-r--r--NorthstarDLL/memalloc.cpp2
-rw-r--r--NorthstarDLL/memalloc.h2
-rw-r--r--NorthstarDLL/modmanager.cpp41
-rw-r--r--NorthstarDLL/modmanager.h4
-rw-r--r--NorthstarDLL/pch.h4
-rw-r--r--NorthstarDLL/rpakfilesystem.cpp18
-rw-r--r--NorthstarDLL/rpakfilesystem.h76
-rw-r--r--NorthstarDLL/serverauthentication.cpp7
-rw-r--r--NorthstarDLL/serverauthentication.h1
-rw-r--r--NorthstarDLL/squirrel.cpp185
-rw-r--r--NorthstarDLL/squirrel.h649
28 files changed, 1018 insertions, 251 deletions
diff --git a/NorthstarDLL/NorthstarDLL.vcxproj b/NorthstarDLL/NorthstarDLL.vcxproj
index fcfbde57..f9f11ba7 100644
--- a/NorthstarDLL/NorthstarDLL.vcxproj
+++ b/NorthstarDLL/NorthstarDLL.vcxproj
@@ -91,7 +91,7 @@
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
- <LanguageStandard>stdcpp17</LanguageStandard>
+ <LanguageStandard>stdcpp20</LanguageStandard>
<AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
@@ -614,10 +614,12 @@
<ClCompile Include="rpakfilesystem.cpp" />
<ClCompile Include="runframe.cpp" />
<ClCompile Include="scriptbrowserhooks.cpp" />
+ <ClCompile Include="scriptjson.cpp" />
<ClCompile Include="scriptmainmenupromos.cpp" />
<ClCompile Include="scriptmodmenu.cpp" />
<ClCompile Include="scriptserverbrowser.cpp" />
<ClCompile Include="scriptsrson.cpp" />
+ <ClCompile Include="scriptutility.cpp" />
<ClCompile Include="serverauthentication.cpp" />
<ClCompile Include="miscserverscript.cpp" />
<ClCompile Include="serverchathooks.cpp" />
diff --git a/NorthstarDLL/NorthstarDLL.vcxproj.filters b/NorthstarDLL/NorthstarDLL.vcxproj.filters
index 555e6481..5f40a53c 100644
--- a/NorthstarDLL/NorthstarDLL.vcxproj.filters
+++ b/NorthstarDLL/NorthstarDLL.vcxproj.filters
@@ -148,6 +148,9 @@
<Filter Include="Header Files\Dedicated Server">
<UniqueIdentifier>{0f1ba4c4-78ee-4b05-afa5-6f598063f5c1}</UniqueIdentifier>
</Filter>
+ <Filter Include="Source Files\Scripted">
+ <UniqueIdentifier>{a3afb0d7-6129-40e5-87a5-2f6758f7e4f6}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
@@ -1682,6 +1685,12 @@
<ClCompile Include="exploitfixes_lzss.cpp">
<Filter>Source Files\Exploit Fixes</Filter>
</ClCompile>
+ <ClCompile Include="scriptutility.cpp">
+ <Filter>Source Files\Scripted</Filter>
+ </ClCompile>
+ <ClCompile Include="scriptjson.cpp">
+ <Filter>Source Files\Scripted</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<MASM Include="audio_asm.asm">
diff --git a/NorthstarDLL/audio.cpp b/NorthstarDLL/audio.cpp
index 30bf92fb..c298687a 100644
--- a/NorthstarDLL/audio.cpp
+++ b/NorthstarDLL/audio.cpp
@@ -196,7 +196,7 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa
std::string pathString = file.path().string();
// Open the file.
- std::basic_ifstream<uint8_t> wavStream(pathString, std::ios::binary);
+ std::ifstream wavStream(pathString, std::ios::binary);
if (wavStream.fail())
{
@@ -221,7 +221,7 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa
[pathString, fileSize, data]
{
std::shared_lock lock(g_CustomAudioManager.m_loadingMutex);
- std::basic_ifstream<uint8_t> wavStream(pathString, std::ios::binary);
+ std::ifstream wavStream(pathString, std::ios::binary);
// would be weird if this got hit, since it would've worked previously
if (wavStream.fail())
@@ -232,7 +232,7 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa
// read from after the header first to preserve the empty header, then read the header last
wavStream.seekg(0, std::ios::beg);
- wavStream.read(data, fileSize);
+ wavStream.read(reinterpret_cast<char*>(data), fileSize);
wavStream.close();
spdlog::info("Finished async read of audio sample {}", pathString);
diff --git a/NorthstarDLL/bansystem.cpp b/NorthstarDLL/bansystem.cpp
index cddc4837..4a5ef30b 100644
--- a/NorthstarDLL/bansystem.cpp
+++ b/NorthstarDLL/bansystem.cpp
@@ -11,21 +11,39 @@
#include <filesystem>
const char* BANLIST_PATH_SUFFIX = "/banlist.txt";
+const char BANLIST_COMMENT_CHAR = '#';
ServerBanSystem* g_pBanSystem;
void ServerBanSystem::OpenBanlist()
{
- std::ifstream enabledModsStream(GetNorthstarPrefix() + "/banlist.txt");
- std::stringstream enabledModsStringStream;
+ std::ifstream banlistStream(GetNorthstarPrefix() + "/banlist.txt");
- if (!enabledModsStream.fail())
+ if (!banlistStream.fail())
{
std::string line;
- while (std::getline(enabledModsStream, line))
- m_vBannedUids.push_back(strtoull(line.c_str(), nullptr, 10));
+ while (std::getline(banlistStream, line))
+ {
+ // ignore line if first char is # or line is empty
+ if (line == "" || line.front() == BANLIST_COMMENT_CHAR)
+ continue;
+
+ // remove tabs which shouldnt be there but maybe someone did the funny
+ line.erase(std::remove(line.begin(), line.end(), '\t'), line.end());
+ // remove spaces to allow for spaces before uids
+ line.erase(std::remove(line.begin(), line.end(), ' '), line.end());
+
+ // check if line is empty to allow for newlines in the file
+ if (line == "")
+ continue;
+
+ // for inline comments like: 123123123 #banned for unfunny
+ std::string uid = line.substr(0, line.find(BANLIST_COMMENT_CHAR));
+
+ m_vBannedUids.push_back(strtoull(uid.c_str(), nullptr, 10));
+ }
- enabledModsStream.close();
+ banlistStream.close();
}
// open write stream for banlist
@@ -43,6 +61,14 @@ void ServerBanSystem::ClearBanlist()
void ServerBanSystem::BanUID(uint64_t uid)
{
+ // checking if last char is \n to make sure uids arent getting fucked
+ std::ifstream fsBanlist(GetNorthstarPrefix() + "/banlist.txt");
+ std::string content((std::istreambuf_iterator<char>(fsBanlist)), (std::istreambuf_iterator<char>()));
+ fsBanlist.close();
+
+ if (content.back() != '\n')
+ m_sBanlistStream << std::endl;
+
m_vBannedUids.push_back(uid);
m_sBanlistStream << std::to_string(uid) << std::endl;
spdlog::info("{} was banned", uid);
@@ -55,9 +81,76 @@ void ServerBanSystem::UnbanUID(uint64_t uid)
return;
m_vBannedUids.erase(findResult);
+
+ std::vector<std::string> banlistText;
+ std::ifstream fs_readBanlist(GetNorthstarPrefix() + "/banlist.txt");
+
+ if (!fs_readBanlist.fail())
+ {
+ std::string line;
+ while (std::getline(fs_readBanlist, line))
+ {
+ // support for comments and newlines added in https://github.com/R2Northstar/NorthstarLauncher/pull/227
+
+ std::string modLine = line; // copy the line into a free var that we can fuck with, line will be the original
+
+ // remove tabs which shouldnt be there but maybe someone did the funny
+ modLine.erase(std::remove(modLine.begin(), modLine.end(), '\t'), modLine.end());
+ // remove spaces to allow for spaces before uids
+ modLine.erase(std::remove(modLine.begin(), modLine.end(), ' '), modLine.end());
+
+ // ignore line if first char is # or empty line, just add it
+ if (line.front() == BANLIST_COMMENT_CHAR || modLine == "")
+ {
+ banlistText.push_back(line);
+ continue;
+ }
+
+ // for inline comments like: 123123123 #banned for unfunny
+ std::string lineUid = line.substr(0, line.find(BANLIST_COMMENT_CHAR));
+ // have to erase spaces or else inline comments will fuck up the uid finding
+ lineUid.erase(std::remove(lineUid.begin(), lineUid.end(), '\t'), lineUid.end());
+ lineUid.erase(std::remove(lineUid.begin(), lineUid.end(), ' '), lineUid.end());
+
+ // if the uid in the line is the uid we wanna unban
+ if (std::to_string(uid) == lineUid)
+ {
+ // comment the uid out
+ line.insert(0, "# ");
+
+ // add a comment with unban date
+ // not necessary but i feel like this makes it better
+ std::time_t t = std::time(0);
+ std::tm* now = std::localtime(&t);
+
+ std::ostringstream unbanComment;
+
+ //{y}/{m}/{d} {h}:{m}
+ unbanComment << " # unban date: ";
+ unbanComment << now->tm_year + 1900 << "-"; // this lib is so fucking awful
+ unbanComment << std::setw(2) << std::setfill('0') << now->tm_mon + 1 << "-";
+ unbanComment << std::setw(2) << std::setfill('0') << now->tm_mday << " ";
+ unbanComment << std::setw(2) << std::setfill('0') << now->tm_hour << ":";
+ unbanComment << std::setw(2) << std::setfill('0') << now->tm_min;
+
+ line.append(unbanComment.str());
+ }
+
+ banlistText.push_back(line);
+ }
+
+ fs_readBanlist.close();
+ }
+
+ // open write stream for banlist // without append so we clear the file
+ if (m_sBanlistStream.is_open())
+ m_sBanlistStream.close();
+ m_sBanlistStream.open(GetNorthstarPrefix() + "/banlist.txt", std::ofstream::out | std::ofstream::binary);
+
+ for (std::string updatedLine : banlistText)
+ m_sBanlistStream << updatedLine << std::endl;
+
spdlog::info("{} was unbanned", uid);
- // todo: this needs to erase from the banlist file
- // atm unsure how to do this aside from just clearing and fully rewriting the file
}
bool ServerBanSystem::IsUIDAllowed(uint64_t uid)
@@ -76,7 +169,7 @@ void ConCommand_ban(const CCommand& args)
if (!strcmp(player->m_Name, args.Arg(1)) || !strcmp(player->m_UID, args.Arg(1)))
{
- g_pBanSystem->BanUID(strtoull((char*)player + 0xF500, nullptr, 10));
+ g_pBanSystem->BanUID(strtoull(player->m_UID, nullptr, 10));
R2::CBaseClient__Disconnect(player, 1, "Banned from server");
break;
}
diff --git a/NorthstarDLL/chatcommand.cpp b/NorthstarDLL/chatcommand.cpp
index 83b352ad..05404363 100644
--- a/NorthstarDLL/chatcommand.cpp
+++ b/NorthstarDLL/chatcommand.cpp
@@ -5,7 +5,7 @@
// note: isIngameChat is an int64 because the whole register the arg is stored in needs to be 0'd out to work
// if isIngameChat is false, we use network chat instead
-typedef void(__fastcall* ClientSayTextType)(void* a1, const char* message, __int64 isIngameChat, bool isTeamChat);
+typedef void(__fastcall* ClientSayTextType)(void* a1, const char* message, uint64_t isIngameChat, bool isTeamChat);
ClientSayTextType ClientSayText;
void ConCommand_say(const CCommand& args)
diff --git a/NorthstarDLL/clientvideooverrides.cpp b/NorthstarDLL/clientvideooverrides.cpp
index 11ca3df4..6d5c9053 100644
--- a/NorthstarDLL/clientvideooverrides.cpp
+++ b/NorthstarDLL/clientvideooverrides.cpp
@@ -33,4 +33,8 @@ void*,, (const char* path, uint32_t flags))
ON_DLL_LOAD_CLIENT("client.dll", BinkVideo, (CModule module))
{
AUTOHOOK_DISPATCH()
+
+ // remove engine check for whether the bik we're trying to load exists in r2/media, as this will fail for biks in mods
+ // note: the check in engine is actually unnecessary, so it's just useless in practice and we lose nothing by removing it
+ module.Offset(0x459AD).NOP(6);
}
diff --git a/NorthstarDLL/convar.cpp b/NorthstarDLL/convar.cpp
index 538f27bd..c8f63922 100644
--- a/NorthstarDLL/convar.cpp
+++ b/NorthstarDLL/convar.cpp
@@ -4,6 +4,8 @@
#include "convar.h"
#include "sourceinterface.h"
+#include <float.h>
+
typedef void (*ConVarRegisterType)(
ConVar* pConVar,
const char* pszName,
diff --git a/NorthstarDLL/debugoverlay.cpp b/NorthstarDLL/debugoverlay.cpp
index b97b2dd8..18975830 100644
--- a/NorthstarDLL/debugoverlay.cpp
+++ b/NorthstarDLL/debugoverlay.cpp
@@ -41,7 +41,7 @@ struct OverlayBase_t
int m_nServerCount; // Latch server count, too
float m_flEndTime; // When does this box go away
OverlayBase_t* m_pNextOverlay;
- __int64 m_pUnk;
+ void* m_pUnk;
};
struct OverlayLine_t : public OverlayBase_t
diff --git a/NorthstarDLL/dllmain.cpp b/NorthstarDLL/dllmain.cpp
index 6e3c313e..aa808bf5 100644
--- a/NorthstarDLL/dllmain.cpp
+++ b/NorthstarDLL/dllmain.cpp
@@ -18,7 +18,7 @@
#include <filesystem>
namespace fs = std::filesystem;
-typedef void (*initPluginFuncPtr)(void* getPluginObject);
+ typedef void (*initPluginFuncPtr)(void* (*getPluginObject)(PluginObject));
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
@@ -79,7 +79,7 @@ bool LoadPlugins()
spdlog::info("Failed to load library {}: ", std::system_category().message(GetLastError()));
continue;
}
- HRSRC manifestResource = FindResourceW(datafile, MAKEINTRESOURCE(101), MAKEINTRESOURCE(RT_RCDATA));
+ HRSRC manifestResource = FindResourceW(datafile, MAKEINTRESOURCEW(101), MAKEINTRESOURCEW(RT_RCDATA));
if (manifestResource == NULL)
{
diff --git a/NorthstarDLL/exploitfixes.cpp b/NorthstarDLL/exploitfixes.cpp
index a5d377b4..4ce9f351 100644
--- a/NorthstarDLL/exploitfixes.cpp
+++ b/NorthstarDLL/exploitfixes.cpp
@@ -33,35 +33,17 @@ bool ValidateFloats(float a, float b = 0, float c = 0)
return !isnan(a) && !isnan(b) && !isnan(c);
}
-struct Vector
+struct Float3
{
- float x, y, z;
+ float vals[3];
- Vector(float x = 0, float y = 0, float z = 0) : x(x), y(y), z(z) {}
-
- bool IsValid()
- {
- return ValidateFloats(x, y, z);
- }
-};
-
-struct Angle
-{
- float pitch, yaw, roll;
-
- Angle(float pitch = 0, float yaw = 0, float roll = 0) : pitch(pitch), yaw(yaw), roll(roll) {}
-
- bool IsInvalid()
+ void MakeValid()
{
- return !ValidateFloats(pitch, yaw, roll);
-
- if (!ValidateFloats(pitch, yaw, roll))
- return false;
-
- return (pitch > 90 || pitch < -90) || (yaw > 180 || yaw < -180) || (roll > 180 || roll < -180);
+ for (auto& val : vals)
+ if (isnan(val))
+ val = 0;
}
};
-
// block bad netmessages
// Servers can literally request a screenshot from any client, yeah no
AUTOHOOK(CLC_Screenshot_WriteToBuffer, engine.dll + 0x22AF20,
@@ -232,16 +214,16 @@ void, __fastcall, (void* buf, void* pCmd_move, void* pCmd_from)) // 4C 89 44 24
ReadUsercmd(buf, pCmd_move, pCmd_from);
// Now let's make sure the CMD we read isnt messed up to prevent numerous exploits (including server crashing)
- struct __declspec(align(4)) SV_CUserCmd
+ struct alignas(4) SV_CUserCmd
{
DWORD command_number;
DWORD tick_count;
float command_time;
- Angle worldViewAngles;
+ Float3 worldViewAngles;
BYTE gap18[4];
- Angle localViewAngles;
- Angle attackangles;
- Vector move;
+ Float3 localViewAngles;
+ Float3 attackangles;
+ Float3 move;
DWORD buttons;
BYTE impulse;
short weaponselect;
@@ -249,8 +231,8 @@ void, __fastcall, (void* buf, void* pCmd_move, void* pCmd_from)) // 4C 89 44 24
BYTE gap4C[24];
char headoffset;
BYTE gap65[11];
- Vector cameraPos;
- Angle cameraAngles;
+ Float3 cameraPos;
+ Float3 cameraAngles;
BYTE gap88[4];
int tickSomething;
DWORD dword90;
@@ -265,29 +247,17 @@ void, __fastcall, (void* buf, void* pCmd_move, void* pCmd_from)) // 4C 89 44 24
std::string BLOCK_PREFIX =
"ReadUsercmd (command_number delta: " + std::to_string(cmd->command_number - fromCmd->command_number) + "): ";
- if (cmd->worldViewAngles.IsInvalid())
- {
- BLOCKED_INFO("CMD has invalid worldViewAngles");
- goto INVALID_CMD;
- }
+ // fix invalid player angles
+ cmd->worldViewAngles.MakeValid();
+ cmd->attackangles.MakeValid();
+ cmd->localViewAngles.MakeValid();
- if (cmd->attackangles.IsInvalid())
- {
- BLOCKED_INFO("CMD has invalid attackangles");
- goto INVALID_CMD;
- }
+ // Fix invalid camera angles
+ cmd->cameraPos.MakeValid();
+ cmd->cameraAngles.MakeValid();
- if (cmd->localViewAngles.IsInvalid())
- {
- BLOCKED_INFO("CMD has invalid localViewAngles");
- goto INVALID_CMD;
- }
-
- if (cmd->cameraAngles.IsInvalid())
- {
- BLOCKED_INFO("CMD has invalid cameraAngles");
- goto INVALID_CMD;
- }
+ // Fix invaid movement vector
+ cmd->move.MakeValid();
if (cmd->frameTime <= 0 || cmd->tick_count == 0 || cmd->command_time <= 0)
{
@@ -297,27 +267,15 @@ void, __fastcall, (void* buf, void* pCmd_move, void* pCmd_from)) // 4C 89 44 24
goto INVALID_CMD; // No simulation of bogus-timed cmds
}
- if (!cmd->move.IsValid())
- {
- BLOCKED_INFO("Invalid move vector");
- goto INVALID_CMD;
- }
-
- if (!cmd->cameraPos.IsValid())
- {
- BLOCKED_INFO("Invalid cameraPos"); // IIRC this can crash spectating clients or anyone watching replays
- goto INVALID_CMD;
- }
-
return;
INVALID_CMD:
// Fix any gameplay-affecting cmd properties
// NOTE: Currently tickcount/frametime is set to 0, this ~shouldn't~ cause any problems
- cmd->worldViewAngles = cmd->localViewAngles = cmd->attackangles = cmd->cameraAngles = Angle(0, 0, 0);
+ cmd->worldViewAngles = cmd->localViewAngles = cmd->attackangles = cmd->cameraAngles = {0, 0, 0};
cmd->tick_count = cmd->frameTime = 0;
- cmd->move = cmd->cameraPos = Vector(0, 0, 0);
+ cmd->move = cmd->cameraPos = {0, 0, 0};
cmd->buttons = 0;
cmd->meleetarget = 0;
}
diff --git a/NorthstarDLL/exploitfixes_utf8parser.cpp b/NorthstarDLL/exploitfixes_utf8parser.cpp
index 84b7cbc6..581596a7 100644
--- a/NorthstarDLL/exploitfixes_utf8parser.cpp
+++ b/NorthstarDLL/exploitfixes_utf8parser.cpp
@@ -176,7 +176,13 @@ bool, __fastcall, (INT64* a1, DWORD* a2, char* strData)) // 48 89 5C 24 ? 48 89
static void* targetRetAddr = CModule("engine.dll").FindPattern("84 C0 75 2C 49 8B 16");
// only call if we're parsing utf8 data from the network (i.e. communities), otherwise we get perf issues
- if (_ReturnAddress() == targetRetAddr && !CheckUTF8Valid(a1, a2, strData))
+ if (
+#ifdef _MSC_VER
+ _ReturnAddress()
+#else
+ __builtin_return_address(0)
+#endif
+ == targetRetAddr && !CheckUTF8Valid(a1, a2, strData))
return false;
return Rson_ParseUTF8(a1, a2, strData);
diff --git a/NorthstarDLL/filesystem.cpp b/NorthstarDLL/filesystem.cpp
index 7fa65d17..9fba160f 100644
--- a/NorthstarDLL/filesystem.cpp
+++ b/NorthstarDLL/filesystem.cpp
@@ -115,7 +115,7 @@ bool,, (IFileSystem* filesystem, char* pPath, void* result))
// force modded files to be read from mods, not vpk
AUTOHOOK(ReadFileFromVPK, filesystem_stdio.dll + 0x5CBA0,
-FileHandle_t,, (VPKData* vpkInfo, __int64* b, char* filename))
+FileHandle_t,, (VPKData* vpkInfo, uint64_t* b, char* filename))
{
// don't compile here because this is only ever called from OpenEx, which already compiles
if (TryReplaceFile(filename, false))
diff --git a/NorthstarDLL/hoststate.cpp b/NorthstarDLL/hoststate.cpp
index 287b4625..c0d6b3b9 100644
--- a/NorthstarDLL/hoststate.cpp
+++ b/NorthstarDLL/hoststate.cpp
@@ -39,6 +39,9 @@ void,, (CHostState* self))
if (g_pServerAuthentication->m_bNeedLocalAuthForNewgame)
SetCurrentPlaylist("tdm");
+ // don't require authentication on singleplayer startup
+ g_pServerAuthentication->m_bRequireClientAuth = strncmp(g_pHostState->m_levelName, "sp_", 3);
+
ServerStartingOrChangingMap();
double dStartTime = Tier0::Plat_FloatTime();
@@ -90,7 +93,6 @@ void, __fastcall, (CHostState* self, double flCurrentTime, float flFrameTime))
// update server presence
g_pServerPresence->RunFrame(flCurrentTime);
}
-
}
ON_DLL_LOAD_RELIESON("engine.dll", HostState, ConVar, (CModule module))
diff --git a/NorthstarDLL/latencyflex.cpp b/NorthstarDLL/latencyflex.cpp
index b9d232b2..7b5a8ebf 100644
--- a/NorthstarDLL/latencyflex.cpp
+++ b/NorthstarDLL/latencyflex.cpp
@@ -5,14 +5,12 @@ AUTOHOOK_INIT()
ConVar* Cvar_r_latencyflex;
-HMODULE m_lfxModule {};
-typedef void (*PFN_winelfx_WaitAndBeginFrame)();
-PFN_winelfx_WaitAndBeginFrame m_winelfx_WaitAndBeginFrame {};
+void (*m_winelfx_WaitAndBeginFrame)();
AUTOHOOK(OnRenderStart, client.dll + 0x1952C0,
void,, ())
{
- if (Cvar_r_latencyflex->GetInt())
+ if (Cvar_r_latencyflex->GetBool() && m_winelfx_WaitAndBeginFrame)
m_winelfx_WaitAndBeginFrame();
OnRenderStart();
@@ -23,9 +21,15 @@ ON_DLL_LOAD_CLIENT_RELIESON("client.dll", LatencyFlex, ConVar, (CModule module))
// Connect to the LatencyFleX service
// LatencyFleX is an open source vendor agnostic replacement for Nvidia Reflex input latency reduction technology.
// https://ishitatsuyuki.github.io/post/latencyflex/
- m_lfxModule = LoadLibraryA("latencyflex_wine.dll");
-
- if (m_lfxModule == nullptr)
+ HMODULE pLfxModule;
+
+ if (pLfxModule = LoadLibraryA("latencyflex_layer.dll"))
+ m_winelfx_WaitAndBeginFrame = reinterpret_cast<void (*)()>(
+ reinterpret_cast<void*>(GetProcAddress(pLfxModule, "lfx_WaitAndBeginFrame")));
+ else if (pLfxModule = LoadLibraryA("latencyflex_wine.dll"))
+ m_winelfx_WaitAndBeginFrame = reinterpret_cast<void (*)()>(
+ reinterpret_cast<void*>(GetProcAddress(pLfxModule, "winelfx_WaitAndBeginFrame")));
+ else
{
spdlog::info("Unable to load LatencyFleX library, LatencyFleX disabled.");
return;
@@ -33,9 +37,6 @@ ON_DLL_LOAD_CLIENT_RELIESON("client.dll", LatencyFlex, ConVar, (CModule module))
AUTOHOOK_DISPATCH()
- m_winelfx_WaitAndBeginFrame =
- reinterpret_cast<PFN_winelfx_WaitAndBeginFrame>(reinterpret_cast<void*>(GetProcAddress(m_lfxModule, "winelfx_WaitAndBeginFrame")));
spdlog::info("LatencyFleX initialized.");
-
Cvar_r_latencyflex = new ConVar("r_latencyflex", "1", FCVAR_ARCHIVE, "Whether or not to use LatencyFleX input latency reduction.");
}
diff --git a/NorthstarDLL/logging.cpp b/NorthstarDLL/logging.cpp
index d238394b..e82c2131 100644
--- a/NorthstarDLL/logging.cpp
+++ b/NorthstarDLL/logging.cpp
@@ -8,7 +8,6 @@
#include <iomanip>
#include <sstream>
-#include <Psapi.h>
AUTOHOOK_INIT()
@@ -127,7 +126,7 @@ void,, (const char* text, ...))
}
AUTOHOOK(CClientState_ProcessPrint, engine.dll + 0x1A1530,
-bool,, (__int64 thisptr, __int64 msg))
+bool,, (void* thisptr, uintptr_t msg))
{
char* text = *(char**)(msg + 0x20);
diff --git a/NorthstarDLL/masterserver.h b/NorthstarDLL/masterserver.h
index efa938cc..5a4e2a91 100644
--- a/NorthstarDLL/masterserver.h
+++ b/NorthstarDLL/masterserver.h
@@ -1,7 +1,7 @@
#pragma once
#include "convar.h"
#include "serverpresence.h"
-#include <WinSock2.h>
+#include <winsock2.h>
#include <string>
#include <cstring>
diff --git a/NorthstarDLL/maxplayers.cpp b/NorthstarDLL/maxplayers.cpp
index c340541a..ba165bee 100644
--- a/NorthstarDLL/maxplayers.cpp
+++ b/NorthstarDLL/maxplayers.cpp
@@ -71,7 +71,7 @@ template <class T> void ChangeOffset(MemoryAddress addr, unsigned int offset)
}
AUTOHOOK(StringTables_CreateStringTable, engine.dll + 0x22E220,
-void*,, (__int64 thisptr, const char* name, int maxentries, int userdatafixedsize, int userdatanetworkbits, int flags))
+void*,, (void* thisptr, const char* name, int maxentries, int userdatafixedsize, int userdatanetworkbits, int flags))
{
// Change the amount of entries to account for a bigger player amount
if (!strcmp(name, "userinfo"))
@@ -181,7 +181,7 @@ void,, (bool a1, float a2))
v3 = *(unsigned char*)(g_pGlobals + 73);
if (*(DWORD*)(qword_1814D9648 + 92) &&
- ((*(unsigned __int8(__fastcall**)(__int64))(*(__int64*)g_pEngineServer + 32i64))(g_pEngineServer) ||
+ ((*(unsigned __int8(__fastcall**)(__int64))(*(__int64*)g_pEngineServer + 32))(g_pEngineServer) ||
!*(DWORD*)(qword_1814DA408 + 92)) &&
v3)
{
@@ -251,7 +251,7 @@ void,, (bool a1, float a2))
if (v23)
v19 = 1;
else
- *v21 = 0i64;
+ *v21 = 0;
}
++v20;
++v21;
diff --git a/NorthstarDLL/memalloc.cpp b/NorthstarDLL/memalloc.cpp
index f16aaed0..8c0fafc8 100644
--- a/NorthstarDLL/memalloc.cpp
+++ b/NorthstarDLL/memalloc.cpp
@@ -68,7 +68,7 @@ void* operator new(size_t n)
return _malloc_base(n);
}
-void operator delete(void* p)
+void operator delete(void* p) noexcept
{
_free_base(p);
} // /FORCE:MULTIPLE
diff --git a/NorthstarDLL/memalloc.h b/NorthstarDLL/memalloc.h
index a1b16ad4..fdd6474b 100644
--- a/NorthstarDLL/memalloc.h
+++ b/NorthstarDLL/memalloc.h
@@ -11,7 +11,7 @@ extern "C" void _free_base(void* const block);
extern "C" char* _strdup_base(const char* src);
void* operator new(size_t n);
-void operator delete(void* p);
+void operator delete(void* p) noexcept;
// void* malloc(size_t n);
diff --git a/NorthstarDLL/modmanager.cpp b/NorthstarDLL/modmanager.cpp
index 76280ef9..8ba883a3 100644
--- a/NorthstarDLL/modmanager.cpp
+++ b/NorthstarDLL/modmanager.cpp
@@ -231,6 +231,26 @@ Mod::Mod(fs::path modDir, char* jsonBuf)
}
}
+ if (modJson.HasMember("Dependencies") && modJson["Dependencies"].IsObject())
+ {
+ for (auto v = modJson["Dependencies"].MemberBegin(); v != modJson["Dependencies"].MemberEnd(); v++)
+ {
+ if (!v->name.IsString() || !v->value.IsString())
+ continue;
+
+ spdlog::info("Constant {} defined by {} for mod {}", v->name.GetString(), Name, v->value.GetString());
+ if (DependencyConstants.find(v->name.GetString()) != DependencyConstants.end() &&
+ v->value.GetString() != DependencyConstants[v->name.GetString()])
+ {
+ spdlog::error("A dependency constant with the same name already exists for another mod. Change the constant name.");
+ return;
+ }
+
+ if (DependencyConstants.find(v->name.GetString()) == DependencyConstants.end())
+ DependencyConstants.emplace(v->name.GetString(), v->value.GetString());
+ }
+ }
+
m_bWasReadSuccessfully = true;
}
@@ -257,6 +277,8 @@ void ModManager::LoadMods()
fs::remove_all(GetCompiledAssetsPath());
fs::create_directories(GetModFolderPath());
+ m_DependencyConstants.clear();
+
// read enabled mods cfg
std::ifstream enabledModsStream(GetNorthstarPrefix() + "/enabledmods.json");
std::stringstream enabledModsStringStream;
@@ -298,6 +320,19 @@ void ModManager::LoadMods()
Mod mod(modDir, (char*)jsonStringStream.str().c_str());
+
+ for (auto& pair : mod.DependencyConstants)
+ {
+ if (m_DependencyConstants.find(pair.first) != m_DependencyConstants.end() && m_DependencyConstants[pair.first] != pair.second)
+ {
+ spdlog::error("Constant {} in mod {} already exists in another mod.", pair.first, mod.Name);
+ mod.m_bWasReadSuccessfully = false;
+ break;
+ }
+ if (m_DependencyConstants.find(pair.first) == m_DependencyConstants.end())
+ m_DependencyConstants.emplace(pair);
+ }
+
if (m_bHasEnabledModsCfg && m_EnabledModsCfg.HasMember(mod.Name.c_str()))
mod.m_bEnabled = m_EnabledModsCfg[mod.Name.c_str()].IsTrue();
else
@@ -428,6 +463,12 @@ void ModManager::LoadMods()
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();
+
modPak.m_sPakName = pakName;
// not using atm because we need to resolve path to rpak
diff --git a/NorthstarDLL/modmanager.h b/NorthstarDLL/modmanager.h
index 4cd335ff..336ef804 100644
--- a/NorthstarDLL/modmanager.h
+++ b/NorthstarDLL/modmanager.h
@@ -57,6 +57,7 @@ struct ModRpakEntry
public:
bool m_bAutoLoad;
std::string m_sPakName;
+ std::string m_sLoadAfterPak;
};
class Mod
@@ -102,6 +103,8 @@ class Mod
std::unordered_map<std::string, std::string>
RpakAliases; // paks we alias to other rpaks, e.g. to load sp_crashsite paks on the map mp_crashsite
+ std::unordered_map<std::string, std::string> DependencyConstants;
+
public:
Mod(fs::path modPath, char* jsonBuf);
};
@@ -127,6 +130,7 @@ class ModManager
public:
std::vector<Mod> m_LoadedMods;
std::unordered_map<std::string, ModOverrideFile> m_ModFiles;
+ std::unordered_map<std::string, std::string> m_DependencyConstants;
public:
ModManager();
diff --git a/NorthstarDLL/pch.h b/NorthstarDLL/pch.h
index 88835dd1..66543859 100644
--- a/NorthstarDLL/pch.h
+++ b/NorthstarDLL/pch.h
@@ -11,8 +11,8 @@
// add headers that you want to pre-compile here
#include "memalloc.h"
-#include <Windows.h>
-#include <Psapi.h>
+#include <windows.h>
+#include <psapi.h>
#include <set>
#include <map>
#include <filesystem>
diff --git a/NorthstarDLL/rpakfilesystem.cpp b/NorthstarDLL/rpakfilesystem.cpp
index bc2195ba..6c01a2e0 100644
--- a/NorthstarDLL/rpakfilesystem.cpp
+++ b/NorthstarDLL/rpakfilesystem.cpp
@@ -112,6 +112,23 @@ void LoadPreloadPaks()
}
}
+void LoadPostloadPaks(const char* pPath)
+{
+ // note, loading from ./ is necessary otherwise paks will load from gamedir/r2/paks
+ for (Mod& mod : g_pModManager->m_LoadedMods)
+ {
+ if (!mod.m_bEnabled)
+ continue;
+
+ // need to get a relative path of mod to mod folder
+ fs::path modPakPath("./" / mod.m_ModDirectory / "paks");
+
+ for (ModRpakEntry& pak : mod.Rpaks)
+ if (pak.m_sLoadAfterPak == pPath)
+ g_pPakLoadManager->LoadPakAsync((modPakPath / pak.m_sPakName).string().c_str(), ePakLoadSource::CONSTANT);
+ }
+}
+
void LoadCustomMapPaks(char** pakName, bool* bNeedToFreePakName)
{
// whether the vanilla game has this rpak
@@ -192,6 +209,7 @@ int,, (char* pPath, void* unknownSingleton, int flags, void* pCallback0, void* p
// trak the pak
g_pPakLoadManager->TrackLoadedPak(ePakLoadSource::UNTRACKED, iPakHandle, nPathHash);
+ LoadPostloadPaks(pPath);
if (bNeedToFreePakName)
delete[] pPath;
diff --git a/NorthstarDLL/rpakfilesystem.h b/NorthstarDLL/rpakfilesystem.h
index f8774083..4a9a4343 100644
--- a/NorthstarDLL/rpakfilesystem.h
+++ b/NorthstarDLL/rpakfilesystem.h
@@ -1,38 +1,38 @@
-#pragma once
-
-enum class ePakLoadSource
-{
- UNTRACKED = -1, // not a pak we loaded, we shouldn't touch this one
-
- CONSTANT, // should be loaded at all times
- MAP // loaded from a map, should be unloaded when the map is unloaded
-};
-
-struct LoadedPak
-{
- ePakLoadSource m_nLoadSource;
- int m_nPakHandle;
- size_t m_nPakNameHash;
-};
-
-class PakLoadManager
-{
- private:
- std::map<int, LoadedPak> m_vLoadedPaks {};
- std::unordered_map<size_t, int> m_HashToPakHandle {};
-
- public:
- int LoadPakAsync(const char* pPath, const ePakLoadSource nLoadSource);
- void UnloadPak(const int nPakHandle);
- void UnloadMapPaks();
-
- LoadedPak* TrackLoadedPak(ePakLoadSource nLoadSource, int nPakHandle, size_t nPakNameHash);
- void RemoveLoadedPak(int nPakHandle);
-
- LoadedPak* GetPakInfo(const int nPakHandle);
-
- int GetPakHandle(const size_t nPakNameHash);
- int GetPakHandle(const char* pPath);
-};
-
-extern PakLoadManager* g_pPakLoadManager;
+#pragma once
+
+enum class ePakLoadSource
+{
+ UNTRACKED = -1, // not a pak we loaded, we shouldn't touch this one
+
+ CONSTANT, // should be loaded at all times
+ MAP // loaded from a map, should be unloaded when the map is unloaded
+};
+
+struct LoadedPak
+{
+ ePakLoadSource m_nLoadSource;
+ int m_nPakHandle;
+ size_t m_nPakNameHash;
+};
+
+class PakLoadManager
+{
+ private:
+ std::map<int, LoadedPak> m_vLoadedPaks {};
+ std::unordered_map<size_t, int> m_HashToPakHandle {};
+
+ public:
+ int LoadPakAsync(const char* pPath, const ePakLoadSource nLoadSource);
+ void UnloadPak(const int nPakHandle);
+ void UnloadMapPaks();
+
+ LoadedPak* TrackLoadedPak(ePakLoadSource nLoadSource, int nPakHandle, size_t nPakNameHash);
+ void RemoveLoadedPak(int nPakHandle);
+
+ LoadedPak* GetPakInfo(const int nPakHandle);
+
+ int GetPakHandle(const size_t nPakNameHash);
+ int GetPakHandle(const char* pPath);
+};
+
+extern PakLoadManager* g_pPakLoadManager;
diff --git a/NorthstarDLL/serverauthentication.cpp b/NorthstarDLL/serverauthentication.cpp
index 953321e6..e7a7ff00 100644
--- a/NorthstarDLL/serverauthentication.cpp
+++ b/NorthstarDLL/serverauthentication.cpp
@@ -265,7 +265,7 @@ void*,, (
}
AUTOHOOK(CBaseClient__Connect, engine.dll + 0x101740,
-bool,, (R2::CBaseClient* self, char* name, __int64 netchan_ptr_arg, char b_fake_player_arg, __int64 a5, char* Buffer, void* a7))
+bool,, (R2::CBaseClient* self, char* name, void* netchan_ptr_arg, char b_fake_player_arg, void* a5, char* Buffer, void* a7))
{
// try changing name before all else
g_pServerAuthentication->VerifyPlayerName(self, pNextPlayerToken, name);
@@ -284,9 +284,8 @@ bool,, (R2::CBaseClient* self, char* name, __int64 netchan_ptr_arg, char b_fake_
if (strlen(name) >= 64) // fix for name overflow bug
R2::CBaseClient__Disconnect(self, 1, "Invalid name");
- else if (
- !g_pServerAuthentication->AuthenticatePlayer(self, iNextPlayerUid, pNextPlayerToken) &&
- g_pMasterServerManager->m_bRequireClientAuth)
+ else if (!g_pServerAuthentication->AuthenticatePlayer(self, iNextPlayerUid, pNextPlayerToken) &&
+ g_pServerAuthentication->m_bRequireClientAuth)
R2::CBaseClient__Disconnect(self, 1, "Authentication Failed");
g_pServerAuthentication->AddPlayerData(self, pNextPlayerToken);
diff --git a/NorthstarDLL/serverauthentication.h b/NorthstarDLL/serverauthentication.h
index a4c9c470..b010e6b1 100644
--- a/NorthstarDLL/serverauthentication.h
+++ b/NorthstarDLL/serverauthentication.h
@@ -36,6 +36,7 @@ class ServerAuthenticationManager
std::mutex m_AuthDataMutex;
std::unordered_map<std::string, RemoteAuthData> m_RemoteAuthenticationData;
std::unordered_map<R2::CBaseClient*, PlayerAuthenticationData> m_PlayerAuthenticationData;
+ bool m_bRequireClientAuth = true;
bool m_bAllowDuplicateAccounts = false;
bool m_bRunningPlayerAuthThread = false;
bool m_bNeedLocalAuthForNewgame = false;
diff --git a/NorthstarDLL/squirrel.cpp b/NorthstarDLL/squirrel.cpp
index bede510e..8beee760 100644
--- a/NorthstarDLL/squirrel.cpp
+++ b/NorthstarDLL/squirrel.cpp
@@ -20,6 +20,178 @@ const char* GetContextName(ScriptContext context)
}
}
+eSQReturnType SQReturnTypeFromString(const char* pReturnType)
+{
+ static const std::map<std::string, eSQReturnType> sqReturnTypeNameToString = {
+ {"bool", eSQReturnType::Boolean},
+ {"float", eSQReturnType::Float},
+ {"vector", eSQReturnType::Vector},
+ {"int", eSQReturnType::Integer},
+ {"entity", eSQReturnType::Entity},
+ {"string", eSQReturnType::String},
+ {"array", eSQReturnType::Arrays},
+ {"asset", eSQReturnType::Asset},
+ {"table", eSQReturnType::Table}};
+
+ if (sqReturnTypeNameToString.find(pReturnType) != sqReturnTypeNameToString.end())
+ return sqReturnTypeNameToString.at(pReturnType);
+ else
+ return eSQReturnType::Default; // previous default value
+}
+
+const char* SQTypeNameFromID(int iTypeId)
+{
+ switch (iTypeId)
+ {
+ case OT_ASSET:
+ return "asset";
+ case OT_INTEGER:
+ return "int";
+ case OT_BOOL:
+ return "bool";
+ case SQOBJECT_NUMERIC:
+ return "float or int";
+ case OT_NULL:
+ return "null";
+ case OT_VECTOR:
+ return "vector";
+ case 0:
+ return "var";
+ case OT_USERDATA:
+ return "userdata";
+ case OT_FLOAT:
+ return "float";
+ case OT_STRING:
+ return "string";
+ case 0x8000040:
+ return "array";
+ case 0x8000200:
+ return "function";
+ case 0x8100000:
+ return "structdef";
+ case OT_THREAD:
+ return "thread";
+ case OT_FUNCPROTO:
+ return "function";
+ case OT_CLAAS:
+ return "class";
+ case OT_WEAKREF:
+ return "weakref";
+ case 0x8080000:
+ return "unimplemented function";
+ case 0x8200000:
+ return "struct instance";
+ case 0xA000020:
+ return "table";
+ case 0xA008000:
+ return "instance";
+ case 0xA400000:
+ return "entity";
+ default:
+ return "";
+ }
+}
+
+// needed to define implementations for squirrelmanager outside of squirrel.h without compiler errors
+template class SquirrelManager<ScriptContext::SERVER>;
+template class SquirrelManager<ScriptContext::CLIENT>;
+template class SquirrelManager<ScriptContext::UI>;
+
+template <ScriptContext context> void SquirrelManager<context>::VMCreated(void* newSqvm)
+{
+ sqvm = newSqvm;
+ sqvm2 = *((void**)((char*)sqvm + 8)); // honestly not 100% sure on what this is, but alot of functions take it
+
+ for (SQFuncRegistration* funcReg : m_funcRegistrations)
+ {
+ spdlog::info("Registering {} function {}", GetContextName(context), funcReg->squirrelFuncName);
+ RegisterSquirrelFunc(sqvm, funcReg, 1);
+ }
+
+ for (auto& pair : g_pModManager->m_DependencyConstants)
+ {
+ bool bWasFound = false;
+ for (Mod& dependency : g_pModManager->m_LoadedMods)
+ {
+ if (!dependency.m_bEnabled)
+ continue;
+
+ if (dependency.Name == pair.second)
+ {
+ bWasFound = true;
+ break;
+ }
+ }
+
+ defconst(sqvm, pair.first.c_str(), bWasFound);
+ }
+}
+
+template <ScriptContext context> void SquirrelManager<context>::VMDestroyed()
+{
+ sqvm = nullptr;
+}
+
+template <ScriptContext context> void SquirrelManager<context>::ExecuteCode(const char* pCode)
+{
+ if (!sqvm)
+ {
+ spdlog::error("Cannot execute code, {} squirrel vm is not initialised", GetContextName(context));
+ return;
+ }
+
+ spdlog::info("Executing {} script code {} ", GetContextName(context), pCode);
+
+ std::string strCode(pCode);
+ CompileBufferState bufferState = CompileBufferState(strCode);
+
+ SQRESULT compileResult = compilebuffer(&bufferState, "console");
+ spdlog::info("sq_compilebuffer returned {}", PrintSQRESULT.at(compileResult));
+
+ if (compileResult != SQRESULT_ERROR)
+ {
+ pushroottable(sqvm2);
+ SQRESULT callResult = call(sqvm2, 0);
+ spdlog::info("sq_call returned {}", PrintSQRESULT.at(callResult));
+ }
+}
+
+template <ScriptContext context> void SquirrelManager<context>::AddFuncRegistration(
+ std::string returnType, std::string name, std::string argTypes, std::string helpText, SQFunction func)
+{
+ SQFuncRegistration* reg = new SQFuncRegistration;
+
+ reg->squirrelFuncName = new char[name.size() + 1];
+ strcpy((char*)reg->squirrelFuncName, name.c_str());
+ reg->cppFuncName = reg->squirrelFuncName;
+
+ reg->helpText = new char[helpText.size() + 1];
+ strcpy((char*)reg->helpText, helpText.c_str());
+
+ reg->returnTypeString = new char[returnType.size() + 1];
+ strcpy((char*)reg->returnTypeString, returnType.c_str());
+ reg->returnType = SQReturnTypeFromString(returnType.c_str());
+
+ reg->argTypes = new char[argTypes.size() + 1];
+ strcpy((char*)reg->argTypes, argTypes.c_str());
+
+ reg->funcPtr = func;
+
+ m_funcRegistrations.push_back(reg);
+}
+
+template <ScriptContext context> SQRESULT SquirrelManager<context>::setupfunc(const SQChar* funcname)
+{
+ pushroottable(sqvm2);
+ pushstring(sqvm2, funcname, -1);
+
+ SQRESULT result = get(sqvm2, -2);
+ if (result != SQRESULT_ERROR)
+ pushroottable(sqvm2);
+
+ return result;
+}
+
// hooks
template <ScriptContext context> void* (*sq_compiler_create)(void* sqvm, void* a2, void* a3, SQBool bShouldThrowError);
template <ScriptContext context> void* sq_compiler_createHook(void* sqvm, void* a2, void* a3, SQBool bShouldThrowError)
@@ -202,7 +374,9 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module))
g_pSquirrel<ScriptContext::UI> = new SquirrelManager<ScriptContext::UI>;
g_pSquirrel<ScriptContext::CLIENT>->RegisterSquirrelFunc = module.Offset(0x108E0).As<RegisterSquirrelFuncType>();
+ g_pSquirrel<ScriptContext::CLIENT>->__sq_defconst = module.Offset(0x12120).As<sq_defconstType>();
g_pSquirrel<ScriptContext::UI>->RegisterSquirrelFunc = g_pSquirrel<ScriptContext::CLIENT>->RegisterSquirrelFunc;
+ g_pSquirrel<ScriptContext::UI>->__sq_defconst = g_pSquirrel<ScriptContext::CLIENT>->__sq_defconst;
g_pSquirrel<ScriptContext::CLIENT>->__sq_compilebuffer = module.Offset(0x3110).As<sq_compilebufferType>();
g_pSquirrel<ScriptContext::CLIENT>->__sq_pushroottable = module.Offset(0x5860).As<sq_pushroottableType>();
@@ -217,16 +391,23 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module))
g_pSquirrel<ScriptContext::UI>->__sq_newarray = g_pSquirrel<ScriptContext::CLIENT>->__sq_newarray;
g_pSquirrel<ScriptContext::UI>->__sq_arrayappend = g_pSquirrel<ScriptContext::CLIENT>->__sq_arrayappend;
+ g_pSquirrel<ScriptContext::CLIENT>->__sq_newtable = module.Offset(0x3960).As<sq_newtableType>();
+ g_pSquirrel<ScriptContext::CLIENT>->__sq_newslot = module.Offset(0x70B0).As<sq_newslotType>();
+ g_pSquirrel<ScriptContext::UI>->__sq_newtable = g_pSquirrel<ScriptContext::CLIENT>->__sq_newtable;
+ g_pSquirrel<ScriptContext::UI>->__sq_newslot = g_pSquirrel<ScriptContext::CLIENT>->__sq_newslot;
+
g_pSquirrel<ScriptContext::CLIENT>->__sq_pushstring = module.Offset(0x3440).As<sq_pushstringType>();
g_pSquirrel<ScriptContext::CLIENT>->__sq_pushinteger = module.Offset(0x36A0).As<sq_pushintegerType>();
g_pSquirrel<ScriptContext::CLIENT>->__sq_pushfloat = module.Offset(0x3800).As<sq_pushfloatType>();
g_pSquirrel<ScriptContext::CLIENT>->__sq_pushbool = module.Offset(0x3710).As<sq_pushboolType>();
g_pSquirrel<ScriptContext::CLIENT>->__sq_raiseerror = module.Offset(0x8470).As<sq_raiseerrorType>();
+ g_pSquirrel<ScriptContext::CLIENT>->__sq_pushasset = module.Offset(0x3560).As<sq_pushAssetType>();
g_pSquirrel<ScriptContext::UI>->__sq_pushstring = g_pSquirrel<ScriptContext::CLIENT>->__sq_pushstring;
g_pSquirrel<ScriptContext::UI>->__sq_pushinteger = g_pSquirrel<ScriptContext::CLIENT>->__sq_pushinteger;
g_pSquirrel<ScriptContext::UI>->__sq_pushfloat = g_pSquirrel<ScriptContext::CLIENT>->__sq_pushfloat;
g_pSquirrel<ScriptContext::UI>->__sq_pushbool = g_pSquirrel<ScriptContext::CLIENT>->__sq_pushbool;
g_pSquirrel<ScriptContext::UI>->__sq_raiseerror = g_pSquirrel<ScriptContext::CLIENT>->__sq_raiseerror;
+ g_pSquirrel<ScriptContext::UI>->__sq_pushasset = g_pSquirrel<ScriptContext::CLIENT>->__sq_pushasset;
g_pSquirrel<ScriptContext::CLIENT>->__sq_getstring = module.Offset(0x60C0).As<sq_getstringType>();
g_pSquirrel<ScriptContext::CLIENT>->__sq_getinteger = module.Offset(0x60E0).As<sq_getintegerType>();
@@ -272,6 +453,7 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module))
g_pSquirrel<ScriptContext::SERVER> = new SquirrelManager<ScriptContext::SERVER>;
g_pSquirrel<ScriptContext::SERVER>->RegisterSquirrelFunc = module.Offset(0x1DD10).As<RegisterSquirrelFuncType>();
+ g_pSquirrel<ScriptContext::SERVER>->__sq_defconst = module.Offset(0x1F550).As<sq_defconstType>();
g_pSquirrel<ScriptContext::SERVER>->__sq_compilebuffer = module.Offset(0x3110).As<sq_compilebufferType>();
g_pSquirrel<ScriptContext::SERVER>->__sq_pushroottable = module.Offset(0x5840).As<sq_pushroottableType>();
@@ -280,6 +462,9 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module))
g_pSquirrel<ScriptContext::SERVER>->__sq_newarray = module.Offset(0x39F0).As<sq_newarrayType>();
g_pSquirrel<ScriptContext::SERVER>->__sq_arrayappend = module.Offset(0x3C70).As<sq_arrayappendType>();
+ g_pSquirrel<ScriptContext::SERVER>->__sq_newtable = module.Offset(0x3960).As<sq_newtableType>();
+ g_pSquirrel<ScriptContext::SERVER>->__sq_newslot = module.Offset(0x7080).As<sq_newslotType>();
+
g_pSquirrel<ScriptContext::SERVER>->__sq_pushstring = module.Offset(0x3440).As<sq_pushstringType>();
g_pSquirrel<ScriptContext::SERVER>->__sq_pushinteger = module.Offset(0x36A0).As<sq_pushintegerType>();
g_pSquirrel<ScriptContext::SERVER>->__sq_pushfloat = module.Offset(0x3800).As<sq_pushfloatType>();
diff --git a/NorthstarDLL/squirrel.h b/NorthstarDLL/squirrel.h
index fbb645a1..a899ed9b 100644
--- a/NorthstarDLL/squirrel.h
+++ b/NorthstarDLL/squirrel.h
@@ -14,14 +14,28 @@ enum SQRESULT : SQInteger
SQRESULT_NOTNULL = 1,
};
+typedef SQRESULT (*SQFunction)(void* sqvm);
+
+enum class eSQReturnType
+{
+ Float = 0x1,
+ Vector = 0x3,
+ Integer = 0x5,
+ Boolean = 0x6,
+ Entity = 0xD,
+ String = 0x21,
+ Default = 0x20,
+ Arrays = 0x25,
+ Asset = 0x28,
+ Table = 0x26,
+};
+
const std::map<SQRESULT, const char*> PrintSQRESULT = {
{SQRESULT_ERROR, "ERROR"},
{SQRESULT_NULL, "NULL"},
{SQRESULT_NOTNULL, "NOTNULL"}
};
-typedef SQRESULT (*SQFunction)(void* sqvm);
-
struct CompileBufferState
{
const SQChar* buffer;
@@ -36,30 +50,496 @@ struct CompileBufferState
}
};
+struct CallInfo;
+struct SQTable;
+struct SQString;
+struct SQFunctionProto;
+struct SQClosure;
+struct SQSharedState;
+struct StringTable;
+struct SQStructInstance;
+struct SQStructDef;
+struct SQNativeClosure;
+struct SQArray;
+struct SQInstruction;
+
+/* 127 */
+enum SQObjectType : uint32_t
+{
+ _RT_NULL = 0x1,
+ _RT_INTEGER = 0x2,
+ _RT_FLOAT = 0x4,
+ _RT_BOOL = 0x8,
+ _RT_STRING = 0x10,
+ _RT_TABLE = 0x20,
+ _RT_ARRAY = 0x40,
+ _RT_USERDATA = 0x80,
+ _RT_CLOSURE = 0x100,
+ _RT_NATIVECLOSURE = 0x200,
+ _RT_GENERATOR = 0x400,
+ OT_USERPOINTER = 0x800,
+ _RT_USERPOINTER = 0x800,
+ _RT_THREAD = 0x1000,
+ _RT_FUNCPROTO = 0x2000,
+ _RT_CLASS = 0x4000,
+ _RT_INSTANCE = 0x8000,
+ _RT_WEAKREF = 0x10000,
+ OT_VECTOR = 0x40000,
+ SQOBJECT_CANBEFALSE = 0x1000000,
+ OT_NULL = 0x1000001,
+ OT_BOOL = 0x1000008,
+ SQOBJECT_DELEGABLE = 0x2000000,
+ SQOBJECT_NUMERIC = 0x4000000,
+ OT_INTEGER = 0x5000002,
+ OT_FLOAT = 0x5000004,
+ SQOBJECT_REF_COUNTED = 0x8000000,
+ OT_STRING = 0x8000010,
+ OT_ARRAY = 0x8000040,
+ OT_CLOSURE = 0x8000100,
+ OT_NATIVECLOSURE = 0x8000200,
+ OT_ASSET = 0x8000400,
+ OT_THREAD = 0x8001000,
+ OT_FUNCPROTO = 0x8002000,
+ OT_CLAAS = 0x8004000,
+ OT_STRUCT = 0x8200000,
+ OT_WEAKREF = 0x8010000,
+ OT_TABLE = 0xA000020,
+ OT_USERDATA = 0xA000080,
+ OT_INSTANCE = 0xA008000,
+ OT_ENTITY = 0xA400000,
+};
+
+/* 156 */
+union alignas(8) SQObjectValue
+{
+ SQString* asString;
+ SQTable* asTable;
+ SQClosure* asClosure;
+ SQFunctionProto* asFuncProto;
+ SQStructDef* asStructDef;
+ uint64_t asInteger;
+ SQStructInstance* asStructInstance;
+ float asFloat;
+ SQNativeClosure* asNativeClosure;
+ SQArray* asArray;
+};
+
+/* 128 */
+struct alignas(8) SQObject
+{
+ SQObjectType _Type;
+ uint32_t _structOffset;
+ SQObjectValue _VAL;
+};
+
+struct tableNode
+{
+ SQObject val;
+ SQObject key;
+ tableNode* next;
+};
+
+/* 138 */
+struct alignas(8) SQString
+{
+ void* vftable;
+ uint32_t uiRef;
+ uint32_t uiRef1;
+ SQString* _next_maybe;
+ SQSharedState* sharedState;
+ uint32_t length;
+ uint8_t gap_24[4];
+ char _hash[8];
+ char _val[1];
+};
+
+/* 137 */
+struct alignas(8) SQTable
+{
+ void* vftable;
+ uint8_t gap_08[4];
+ uint32_t uiRef;
+ uint8_t gap_10[8];
+ void* pointer_18;
+ void* pointer_20;
+ void* _sharedState;
+ uint64_t field_30;
+ tableNode* _nodes;
+ uint32_t _numOfNodes;
+ uint32_t size;
+ uint32_t field_48;
+ uint32_t _usedNodes;
+ uint8_t _gap_50[20];
+ uint32_t field_64;
+ uint8_t _gap_68[80];
+};
+
+/* 140 */
+struct alignas(8) SQClosure
+{
+ void* vftable;
+ uint8_t gap_08[4];
+ uint32_t uiRef;
+ void* pointer_10;
+ void* pointer_18;
+ void* pointer_20;
+ void* sharedState;
+ SQObject obj_30;
+ SQObject _function;
+ SQObject* _outervalues;
+ uint8_t gap_58[8];
+ uint8_t gap_60[96];
+ SQObject* objectPointer_C0;
+};
+
+/* 139 */
+struct alignas(8) SQFunctionProto
+{
+ void* vftable;
+ uint8_t gap_08[4];
+ uint32_t uiRef;
+ uint8_t gap_10[8];
+ void* pointer_18;
+ void* pointer_20;
+ void* sharedState;
+ void* pointer_30;
+ SQObject fileName;
+ SQObject funcName;
+ SQObject obj_58;
+ uint8_t gap_68[64];
+ uint32_t nParameters;
+ uint8_t gap_AC[60];
+ uint32_t nDefaultParams;
+ uint8_t gap_EC[200];
+};
+
+/* 152 */
+struct SQStructDef
+{
+ uint8_t gap_0[56];
+ SQString* name;
+ uint8_t gap_[300];
+};
+
+/* 150 */
+struct SQStructInstance
+{
+ void* vftable;
+ uint8_t gap_8[16];
+ void* pointer_18;
+ uint8_t gap_20[8];
+ SQSharedState* _sharedState;
+ uint8_t gap_30[8];
+ SQObject data[1];
+};
+
+/* 157 */
+struct alignas(8) SQNativeClosure
+{
+ void* vftable;
+ uint8_t gap_08[4];
+ uint32_t uiRef;
+ uint8_t gap_10[88];
+ SQString* _name;
+ uint8_t gap_0[300];
+};
+
+/* 148 */
+struct SQSharedState
+{
+ uint8_t gap_0[72];
+ StringTable* _stringtable;
+ uint8_t gap_50[30000];
+};
+
+/* 149 */
+struct StringTable
+{
+ uint8_t gap_0[12];
+ int _numofslots;
+ uint8_t gap_10[200];
+};
+
+/* 129 */
+struct alignas(8) HSquirrelVM
+{
+ void* vftable;
+ uint32_t uiRef;
+ uint8_t gap_8[12];
+ void* _toString;
+ void* _roottable_pointer;
+ void* pointer_28;
+ CallInfo* ci;
+ CallInfo* _callsstack;
+ uint32_t _callsstacksize;
+ uint32_t _stackbase;
+ SQObject* _stackOfCurrentFunction;
+ SQSharedState* sharedState;
+ void* pointer_58;
+ void* pointer_60;
+ uint32_t _top;
+ SQObject* _stack;
+ uint8_t gap_78[8];
+ SQObject* _vargsstack;
+ uint8_t gap_88[8];
+ SQObject temp_reg;
+ uint8_t gapA0[8];
+ void* pointer_A8;
+ uint8_t gap_B0[8];
+ SQObject _roottable_object;
+ SQObject _lasterror;
+ SQObject _errorHandler;
+ uint64_t field_E8;
+ uint32_t traps;
+ uint8_t gap_F4[12];
+ uint32_t _nnativecalls;
+ uint32_t _suspended;
+ uint32_t _suspended_root;
+ uint32_t _callstacksize;
+ uint32_t _suspended_target;
+ uint32_t field_114;
+ uint32_t _suspend_varargs;
+ SQObject* _object_pointer_120;
+};
+
+/* 136 */
+struct alignas(8) CallInfo
+{
+ SQInstruction* ip;
+ SQObject* _literals;
+ SQObject obj10;
+ SQObject closure;
+ uint32_t _etraps[4];
+ uint32_t _root;
+ short _vargs_size;
+ short _vargs_base;
+};
+
+/* 135 */
+enum SQOpcode : int
+{
+ _OP_LOAD = 0x0,
+ _OP_LOADCOPY = 0x1,
+ _OP_LOADINT = 0x2,
+ _OP_LOADFLOAT = 0x3,
+ _OP_DLOAD = 0x4,
+ _OP_TAILCALL = 0x5,
+ _OP_CALL = 0x6,
+ _OP_PREPCALL = 0x7,
+ _OP_PREPCALLK = 0x8,
+ _OP_GETK = 0x9,
+ _OP_MOVE = 0xA,
+ _OP_NEWSLOT = 0xB,
+ _OP_DELETE = 0xC,
+ _OP_SET = 0xD,
+ _OP_GET = 0xE,
+ _OP_EQ = 0xF,
+ _OP_NE = 0x10,
+ _OP_ARITH = 0x11,
+ _OP_BITW = 0x12,
+ _OP_RETURN = 0x13,
+ _OP_LOADNULLS = 0x14,
+ _OP_LOADROOTTABLE = 0x15,
+ _OP_LOADBOOL = 0x16,
+ _OP_DMOVE = 0x17,
+ _OP_JMP = 0x18,
+ _OP_JNZ = 0x19,
+ _OP_JZ = 0x1A,
+ _OP_LOADFREEVAR = 0x1B,
+ _OP_VARGC = 0x1C,
+ _OP_GETVARGV = 0x1D,
+ _OP_NEWTABLE = 0x1E,
+ _OP_NEWARRAY = 0x1F,
+ _OP_APPENDARRAY = 0x20,
+ _OP_GETPARENT = 0x21,
+ _OP_COMPOUND_ARITH = 0x22,
+ _OP_COMPOUND_ARITH_LOCAL = 0x23,
+ _OP_INCREMENT_PREFIX = 0x24,
+ _OP_INCREMENT_PREFIX_LOCAL = 0x25,
+ _OP_INCREMENT_PREFIX_STRUCTFIELD = 0x26,
+ _OP_INCREMENT_POSTFIX = 0x27,
+ _OP_INCREMENT_POSTFIX_LOCAL = 0x28,
+ _OP_INCREMENT_POSTFIX_STRUCTFIELD = 0x29,
+ _OP_CMP = 0x2A,
+ _OP_EXISTS = 0x2B,
+ _OP_INSTANCEOF = 0x2C,
+ _OP_NEG = 0x2D,
+ _OP_NOT = 0x2E,
+ _OP_BWNOT = 0x2F,
+ _OP_CLOSURE = 0x30,
+ _OP_FOREACH = 0x31,
+ _OP_FOREACH_STATICARRAY_START = 0x32,
+ _OP_FOREACH_STATICARRAY_NEXT = 0x33,
+ _OP_FOREACH_STATICARRAY_NESTEDSTRUCT_START = 0x34,
+ _OP_FOREACH_STATICARRAY_NESTEDSTRUCT_NEXT = 0x35,
+ _OP_DELEGATE = 0x36,
+ _OP_CLONE = 0x37,
+ _OP_TYPEOF = 0x38,
+ _OP_PUSHTRAP = 0x39,
+ _OP_POPTRAP = 0x3A,
+ _OP_THROW = 0x3B,
+ _OP_CLASS = 0x3C,
+ _OP_NEWSLOTA = 0x3D,
+ _OP_EQ_LITERAL = 0x3E,
+ _OP_NE_LITERAL = 0x3F,
+ _OP_FOREACH_SETUP = 0x40,
+ _OP_ASSERT_FAILED = 0x41,
+ _OP_ADD = 0x42,
+ _OP_SUB = 0x43,
+ _OP_MUL = 0x44,
+ _OP_DIV = 0x45,
+ _OP_MOD = 0x46,
+ _OP_PREPCALLK_CALL = 0x47,
+ _OP_PREPCALLK_MOVE_CALL = 0x48,
+ _OP_PREPCALLK_LOADINT_CALL = 0x49,
+ _OP_CMP_JZ = 0x4A,
+ _OP_INCREMENT_LOCAL_DISCARD_JMP = 0x4B,
+ _OP_JZ_RETURN = 0x4C,
+ _OP_JZ_LOADBOOL_RETURN = 0x4D,
+ _OP_NEWVECTOR = 0x4E,
+ _OP_ZEROVECTOR = 0x4F,
+ _OP_GET_VECTOR_COMPONENT = 0x50,
+ _OP_SET_VECTOR_COMPONENT = 0x51,
+ _OP_VECTOR_COMPONENT_MINUSEQ = 0x52,
+ _OP_VECTOR_COMPONENT_PLUSEQ = 0x53,
+ _OP_VECTOR_COMPONENT_MULEQ = 0x54,
+ _OP_VECTOR_COMPONENT_DIVEQ = 0x55,
+ _OP_VECTOR_NORMALIZE = 0x56,
+ _OP_VECTOR_NORMALIZE_IN_PLACE = 0x57,
+ _OP_VECTOR_DOT_PRODUCT = 0x58,
+ _OP_VECTOR_DOT_PRODUCT2D = 0x59,
+ _OP_VECTOR_CROSS_PRODUCT = 0x5A,
+ _OP_VECTOR_CROSS_PRODUCT2D = 0x5B,
+ _OP_VECTOR_LENGTH = 0x5C,
+ _OP_VECTOR_LENGTHSQR = 0x5D,
+ _OP_VECTOR_LENGTH2D = 0x5E,
+ _OP_VECTOR_LENGTH2DSQR = 0x5F,
+ _OP_VECTOR_DISTANCE = 0x60,
+ _OP_VECTOR_DISTANCESQR = 0x61,
+ _OP_VECTOR_DISTANCE2D = 0x62,
+ _OP_VECTOR_DISTANCE2DSQR = 0x63,
+ _OP_INCREMENT_LOCAL_DISCARD = 0x64,
+ _OP_FASTCALL = 0x65,
+ _OP_FASTCALL_NATIVE = 0x66,
+ _OP_FASTCALL_NATIVE_ARGTYPECHECK = 0x67,
+ _OP_FASTCALL_ENV = 0x68,
+ _OP_FASTCALL_NATIVE_ENV = 0x69,
+ _OP_FASTCALL_NATIVE_ENV_ARGTYPECHECK = 0x6A,
+ _OP_LOADGLOBALARRAY = 0x6B,
+ _OP_GETGLOBAL = 0x6C,
+ _OP_SETGLOBAL = 0x6D,
+ _OP_COMPOUND_ARITH_GLOBAL = 0x6E,
+ _OP_GETSTRUCTFIELD = 0x6F,
+ _OP_SETSTRUCTFIELD = 0x70,
+ _OP_COMPOUND_ARITH_STRUCTFIELD = 0x71,
+ _OP_NEWSTRUCT = 0x72,
+ _OP_GETSUBSTRUCT = 0x73,
+ _OP_GETSUBSTRUCT_DYNAMIC = 0x74,
+ _OP_TYPECAST = 0x75,
+ _OP_TYPECHECK = 0x76,
+ _OP_TYPECHECK_ORNULL = 0x77,
+ _OP_TYPECHECK_NOTNULL = 0x78,
+ _OP_CHECK_ENTITY_CLASS = 0x79,
+ _OP_UNREACHABLE = 0x7A,
+ _OP_ARRAY_RESIZE = 0x7B,
+};
+
+/* 141 */
+struct alignas(8) SQStackInfos
+{
+ char* _name;
+ char* _sourceName;
+ uint32_t _line;
+};
+
+/* 151 */
+struct alignas(4) SQInstruction
+{
+ int op;
+ int arg1;
+ int output;
+ uint16_t arg2;
+ uint16_t arg3;
+};
+
+/* 154 */
+struct SQLexer
+{
+ uint8_t gap_0[112];
+};
+
+/* 153 */
+struct SQCompiler
+{
+ uint8_t gap_0[4];
+ uint32_t _token;
+ uint8_t gap_8[8];
+ SQObject object_10;
+ SQLexer lexer;
+ uint8_t gap_1[768];
+};
+
+/* 155 */
+struct CSquirrelVM
+{
+ uint8_t gap_0[8];
+ HSquirrelVM* sqvm;
+};
+
+struct SQVector
+{
+ SQObjectType _Type;
+ float x;
+ float y;
+ float z;
+};
+
+struct SQArray
+{
+ void* vftable;
+ uint32_t uiRef;
+ uint8_t gap_24[36];
+ SQObject* _values;
+ uint32_t _usedSlots;
+ uint32_t _allocated;
+};
+
+#define SQOBJ_INCREMENT_REFERENCECOUNT(val) \
+ if ((val->_Type & SQOBJECT_REF_COUNTED) != 0) \
+ ++val->_VAL.asString->uiRef;
+
+#define SQOBJ_DECREMENT_REFERENCECOUNT(val) \
+ if ((val->_Type & SQOBJECT_REF_COUNTED) != 0) \
+ { \
+ if (val->_VAL.asString->uiRef-- == 1) \
+ { \
+ spdlog::info("Deleted SQObject of type {} with address {:X}", sq_getTypeName(val->_Type), val->_VAL.asInteger); \
+ (*(void(__fastcall**)(SQString*))(&val->_VAL.asString->vftable[1]))(val->_VAL.asString); \
+ } \
+ }
+
struct SQFuncRegistration
{
const char* squirrelFuncName;
const char* cppFuncName;
const char* helpText;
- const char* returnValueType;
+ const char* returnTypeString;
const char* argTypes;
- int16_t somethingThatsZero;
- int16_t padding1;
- int32_t unknown1;
- int64_t unknown2;
- int32_t unknown3;
- int32_t padding2;
- int64_t unknown4;
- int64_t unknown5;
- int64_t unknown6;
- int32_t unknown7;
- int32_t padding3;
+ uint32_t unknown1;
+ uint32_t devLevel;
+ const char* shortNameMaybe;
+ uint32_t unknown2;
+ eSQReturnType returnType;
+ uint32_t* externalBufferPointer;
+ uint64_t externalBufferSize;
+ uint64_t unknown3;
+ uint64_t unknown4;
void* funcPtr;
SQFuncRegistration()
{
memset(this, 0, sizeof(SQFuncRegistration));
- this->padding2 = 32;
+ this->returnType = eSQReturnType::Default;
}
};
@@ -68,28 +548,35 @@ enum class ScriptContext : int
SERVER,
CLIENT,
UI,
- NONE
};
const char* GetContextName(ScriptContext context);
+eSQReturnType SQReturnTypeFromString(const char* pReturnType);
+const char* SQTypeNameFromID(const int iTypeId);
// core sqvm funcs
typedef int64_t (*RegisterSquirrelFuncType)(void* sqvm, SQFuncRegistration* funcReg, char unknown);
+typedef void (*sq_defconstType)(void* sqvm, const SQChar* name, int value);
typedef SQRESULT (*sq_compilebufferType)(void* sqvm, CompileBufferState* compileBuffer, const char* file, int a1, SQBool bShouldThrowError);
typedef SQRESULT (*sq_callType)(void* sqvm, SQInteger iArgs, SQBool bShouldReturn, SQBool bThrowError);
+typedef SQInteger (*sq_raiseerrorType)(void* sqvm, const SQChar* pError);
// sq stack array funcs
typedef void (*sq_newarrayType)(void* sqvm, SQInteger iStackpos);
typedef SQRESULT (*sq_arrayappendType)(void* sqvm, SQInteger iStackpos);
+// sq table funcs
+typedef SQRESULT (*sq_newtableType)(void* sqvm);
+typedef SQRESULT (*sq_newslotType)(void* sqvm, SQInteger idx, SQBool bStatic);
+
// sq stack push funcs
typedef void (*sq_pushroottableType)(void* sqvm);
typedef void (*sq_pushstringType)(void* sqvm, const SQChar* pStr, SQInteger iLength);
typedef void (*sq_pushintegerType)(void* sqvm, SQInteger i);
typedef void (*sq_pushfloatType)(void* sqvm, SQFloat f);
typedef void (*sq_pushboolType)(void* sqvm, SQBool b);
-typedef SQInteger (*sq_raiseerrorType)(void* sqvm, const SQChar* pError);
+typedef void (*sq_pushAssetType)(void* sqvm, const SQChar* pName, SQInteger iLength);
// sq stack get funcs
typedef const SQChar* (*sq_getstringType)(void* sqvm, SQInteger stackpos);
@@ -111,6 +598,7 @@ template <ScriptContext context> class SquirrelManager
#pragma region SQVM funcs
RegisterSquirrelFuncType RegisterSquirrelFunc;
+ sq_defconstType __sq_defconst;
sq_compilebufferType __sq_compilebuffer;
sq_callType __sq_call;
@@ -119,11 +607,15 @@ template <ScriptContext context> class SquirrelManager
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_getstringType __sq_getstring;
sq_getintegerType __sq_getinteger;
@@ -135,153 +627,104 @@ template <ScriptContext context> class SquirrelManager
public:
SquirrelManager() : sqvm(nullptr) {}
- void VMCreated(void* newSqvm)
- {
- sqvm = newSqvm;
- sqvm2 = *((void**)((char*)sqvm + 8)); // honestly not 100% sure on what this is, but alot of functions take it
-
- for (SQFuncRegistration* funcReg : m_funcRegistrations)
- {
- spdlog::info("Registering {} function {}", GetContextName(context), funcReg->squirrelFuncName);
- RegisterSquirrelFunc(sqvm, funcReg, 1);
- }
- }
-
- void VMDestroyed()
- {
- sqvm = nullptr;
- }
+ void VMCreated(void* newSqvm);
+ void VMDestroyed();
+ void ExecuteCode(const char* code);
+ void AddFuncRegistration(std::string returnType, std::string name, std::string argTypes, std::string helpText, SQFunction func);
+ SQRESULT setupfunc(const SQChar* funcname);
- void ExecuteCode(const char* code)
+ #pragma region SQVM func wrappers
+ inline void defconst(void* sqvm, const SQChar* pName, int nValue)
{
- if (!sqvm)
- {
- spdlog::error("Cannot execute code, {} squirrel vm is not initialised", GetContextName(context));
- return;
- }
-
- spdlog::info("Executing {} script code {} ", GetContextName(context), code);
-
- std::string strCode(code);
- CompileBufferState bufferState = CompileBufferState(strCode);
-
- SQRESULT compileResult = compilebuffer(&bufferState, "console");
- spdlog::info("sq_compilebuffer returned {}", PrintSQRESULT.at(compileResult));
-
- if (compileResult != SQRESULT_ERROR)
- {
- pushroottable(sqvm2);
- SQRESULT callResult = call(sqvm2, 0);
- spdlog::info("sq_call returned {}", PrintSQRESULT.at(callResult));
- }
+ __sq_defconst(sqvm, pName, nValue);
}
- void AddFuncRegistration(std::string returnType, std::string name, std::string argTypes, std::string helpText, SQFunction func)
+ inline SQRESULT compilebuffer(CompileBufferState* bufferState, const SQChar* bufferName = "unnamedbuffer", const SQBool bShouldThrowError = false)
{
- SQFuncRegistration* reg = new SQFuncRegistration;
-
- reg->squirrelFuncName = new char[name.size() + 1];
- strcpy((char*)reg->squirrelFuncName, name.c_str());
- reg->cppFuncName = reg->squirrelFuncName;
-
- reg->helpText = new char[helpText.size() + 1];
- strcpy((char*)reg->helpText, helpText.c_str());
-
- reg->returnValueType = new char[returnType.size() + 1];
- strcpy((char*)reg->returnValueType, returnType.c_str());
-
- reg->argTypes = new char[argTypes.size() + 1];
- strcpy((char*)reg->argTypes, argTypes.c_str());
-
- reg->funcPtr = func;
-
- m_funcRegistrations.push_back(reg);
+ return __sq_compilebuffer(sqvm2, bufferState, bufferName, -1, bShouldThrowError);
}
- SQRESULT setupfunc(const SQChar* funcname)
+ inline SQRESULT call(void* sqvm, const SQInteger args)
{
- pushroottable(sqvm2);
- pushstring(sqvm2, funcname, -1);
-
- SQRESULT result = get(sqvm2, -2);
- if (result != SQRESULT_ERROR)
- pushroottable(sqvm2);
-
- return result;
+ return __sq_call(sqvm, args + 1, false, false);
}
- #pragma region SQVM func wrappers
- SQRESULT compilebuffer(CompileBufferState* bufferState, const SQChar* bufferName = "unnamedbuffer", const SQBool bShouldThrowError = false)
+ inline SQInteger raiseerror(void* sqvm, const const SQChar* sError)
{
- return __sq_compilebuffer(sqvm2, bufferState, bufferName, -1, bShouldThrowError);
+ return __sq_raiseerror(sqvm, sError);
}
- SQRESULT call(void* sqvm, const SQInteger args)
+ inline void newarray(void* sqvm, const SQInteger stackpos = 0)
{
- return __sq_call(sqvm, args + 1, false, false);
+ __sq_newarray(sqvm, stackpos);
}
- SQInteger raiseerror(void* sqvm, const const SQChar* sError)
+ inline SQRESULT arrayappend(void* sqvm, const SQInteger stackpos)
{
- return __sq_raiseerror(sqvm, sError);
+ return __sq_arrayappend(sqvm, stackpos);
}
- void newarray(void* sqvm, const SQInteger stackpos = 0)
+ inline SQRESULT newtable(void* sqvm)
{
- __sq_newarray(sqvm, stackpos);
+ return __sq_newtable(sqvm);
}
- SQRESULT arrayappend(void* sqvm, const SQInteger stackpos)
+ inline SQRESULT newslot(void* sqvm, SQInteger idx, SQBool bStatic)
{
- return __sq_arrayappend(sqvm, stackpos);
+ return __sq_newslot(sqvm, idx, bStatic);
}
- void pushroottable(void* sqvm)
+ inline void pushroottable(void* sqvm)
{
__sq_pushroottable(sqvm);
}
- void pushstring(void* sqvm, const SQChar* sVal, int length = -1)
+ inline void pushstring(void* sqvm, const SQChar* sVal, int length = -1)
{
__sq_pushstring(sqvm, sVal, length);
}
- void pushinteger(void* sqvm, const SQInteger iVal)
+ inline void pushinteger(void* sqvm, const SQInteger iVal)
{
__sq_pushinteger(sqvm, iVal);
}
- void pushfloat(void* sqvm, const SQFloat flVal)
+ inline void pushfloat(void* sqvm, const SQFloat flVal)
{
__sq_pushfloat(sqvm, flVal);
}
- void pushbool(void* sqvm, const SQBool bVal)
+ inline void pushbool(void* sqvm, const SQBool bVal)
{
__sq_pushbool(sqvm, bVal);
}
- const SQChar* getstring(void* sqvm, const SQInteger stackpos)
+ inline void pushasset(void* sqvm, const SQChar* sVal, int length = -1)
+ {
+ __sq_pushasset(sqvm, sVal, length);
+ }
+
+ inline const SQChar* getstring(void* sqvm, const SQInteger stackpos)
{
return __sq_getstring(sqvm, stackpos);
}
- SQInteger getinteger(void* sqvm, const SQInteger stackpos)
+ inline SQInteger getinteger(void* sqvm, const SQInteger stackpos)
{
return __sq_getinteger(sqvm, stackpos);
}
- SQFloat getfloat(void* sqvm, const SQInteger stackpos)
+ inline SQFloat getfloat(void* sqvm, const SQInteger stackpos)
{
return __sq_getfloat(sqvm, stackpos);
}
- SQBool getbool(void* sqvm, const SQInteger stackpos)
+ inline SQBool getbool(void* sqvm, const SQInteger stackpos)
{
return __sq_getbool(sqvm, stackpos);
}
- SQRESULT get(void* sqvm, const SQInteger stackpos)
+ inline SQRESULT get(void* sqvm, const SQInteger stackpos)
{
return __sq_get(sqvm, stackpos);
}