aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDLL
diff options
context:
space:
mode:
Diffstat (limited to 'NorthstarDLL')
-rw-r--r--NorthstarDLL/buildainfile.cpp2
-rw-r--r--NorthstarDLL/dedicated.cpp23
-rw-r--r--NorthstarDLL/exploitfixes.cpp24
-rw-r--r--NorthstarDLL/masterserver.cpp39
-rw-r--r--NorthstarDLL/masterserver.h1
-rw-r--r--NorthstarDLL/printcommands.cpp2
-rw-r--r--NorthstarDLL/printmaps.cpp2
-rw-r--r--NorthstarDLL/r2engine.cpp2
-rw-r--r--NorthstarDLL/r2engine.h2
-rw-r--r--NorthstarDLL/rpakfilesystem.cpp14
-rw-r--r--NorthstarDLL/scriptserverbrowser.cpp9
-rw-r--r--NorthstarDLL/serverpresence.cpp13
-rw-r--r--NorthstarDLL/serverpresence.h2
-rw-r--r--NorthstarDLL/squirrel.cpp6
14 files changed, 115 insertions, 26 deletions
diff --git a/NorthstarDLL/buildainfile.cpp b/NorthstarDLL/buildainfile.cpp
index b759db66..d0397fce 100644
--- a/NorthstarDLL/buildainfile.cpp
+++ b/NorthstarDLL/buildainfile.cpp
@@ -182,7 +182,7 @@ ConVar* Cvar_ns_ai_dumpAINfileFromLoad;
void DumpAINInfo(CAI_Network* aiNetwork)
{
- fs::path writePath(fmt::format("{}/maps/graphs", "r2"));
+ fs::path writePath(fmt::format("{}/maps/graphs", R2::g_pModName));
writePath /= R2::g_pHostState->m_levelName;
writePath += ".ain";
diff --git a/NorthstarDLL/dedicated.cpp b/NorthstarDLL/dedicated.cpp
index 5fd67c33..d8e2992e 100644
--- a/NorthstarDLL/dedicated.cpp
+++ b/NorthstarDLL/dedicated.cpp
@@ -107,7 +107,7 @@ DWORD WINAPI ConsoleInputThread(PVOID pThreadParameter)
{
input += "\n";
Cbuf_AddText(Cbuf_GetCurrentPlayer(), input.c_str(), cmd_source_t::kCommandSrcCode);
- //TryPrintCvarHelpForCommand(input.c_str()); // this needs to be done on main thread, unstable in this one
+ TryPrintCvarHelpForCommand(input.c_str()); // this needs to be done on main thread, unstable in this one
}
}
@@ -264,14 +264,27 @@ ON_DLL_LOAD_DEDI("tier0.dll", DedicatedServerOrigin, (CModule module))
module.GetExport("Tier0_InitOrigin").Patch("C3");
}
-AUTOHOOK(PrintFatalSquirrelError, server.dll + 0x794D0,
+AUTOHOOK(PrintSquirrelError, server.dll + 0x794D0,
void, , (void* sqvm))
{
- PrintFatalSquirrelError(sqvm);
- g_pEngine->m_nQuitting = EngineQuitState::QUIT_TODESKTOP;
+ PrintSquirrelError(sqvm);
+
+ // close dedicated server if a fatal error is hit
+ static ConVar* Cvar_fatal_script_errors = g_pCVar->FindVar("fatal_script_errors");
+ if (Cvar_fatal_script_errors->GetBool())
+ abort();
}
ON_DLL_LOAD_DEDI("server.dll", DedicatedServerGameDLL, (CModule module))
{
- AUTOHOOK_DISPATCH_MODULE("server.dll")
+ AUTOHOOK_DISPATCH_MODULE(server.dll)
+
+ if (Tier0::CommandLine()->CheckParm("-nopakdedi"))
+ {
+ module.Offset(0x6BA350).Patch("C3"); // dont load skins.rson from rpak if we don't have rpaks, as loading it will cause a crash
+ module.Offset(0x6BA300).Patch(
+ "B8 C8 00 00 00 C3"); // return 200 as the number of skins from server.dll + 6BA300, this is the normal value read from
+ // skins.rson and should be updated when we need it more modular
+
+ }
}
diff --git a/NorthstarDLL/exploitfixes.cpp b/NorthstarDLL/exploitfixes.cpp
index 8b5783d6..a5d377b4 100644
--- a/NorthstarDLL/exploitfixes.cpp
+++ b/NorthstarDLL/exploitfixes.cpp
@@ -8,8 +8,12 @@
AUTOHOOK_INIT()
-ConVar* ns_exploitfixes_log;
-#define SHOULD_LOG (ns_exploitfixes_log->m_Value.m_nValue > 0)
+ConVar* Cvar_ns_exploitfixes_log;
+ConVar* Cvar_ns_should_log_all_clientcommands;
+
+ConVar* Cvar_sv_cheats;
+
+#define SHOULD_LOG (Cvar_ns_exploitfixes_log->m_Value.m_nValue > 0)
#define BLOCKED_INFO(s) \
( \
[=]() -> bool \
@@ -323,16 +327,22 @@ INVALID_CMD:
AUTOHOOK(IsRespawnMod, engine.dll + 0x1C6360,
bool, __fastcall, (const char* pModName)) // 48 83 EC 28 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? E8 ? ? ? ? 85 C0 74 63
{
+ // somewhat temp, store the modname here, since we don't have a proper ptr to it rn
+ int iSize = strlen(pModName);
+ R2::g_pModName = new char[iSize + 1];
+ strcpy(R2::g_pModName, pModName);
+
return (!strcmp("r2", pModName) || !strcmp("r1", pModName))
&& !Tier0::CommandLine()->CheckParm("-norestrictservercommands");
}
-// ratelimit stringcmds, and prevent remote clients from calling non-FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS commands
+// ratelimit stringcmds, and prevent remote clients from calling commands that they shouldn't
bool (*CCommand__Tokenize)(CCommand& self, const char* pCommandString, R2::cmd_source_t commandSource);
AUTOHOOK(CGameClient__ExecuteStringCommand,
engine.dll + 0x1022E0, bool, , (R2::CBaseClient* self, uint32_t unknown, const char* pCommandString))
{
- static ConVar* Cvar_sv_cheats = R2::g_pCVar->FindVar("sv_cheats"); // doing this here is temp
+ if (Cvar_ns_should_log_all_clientcommands->GetBool())
+ spdlog::info("player {} (UID: {}) sent command: \"{}\"", self->m_Name, self->m_UID, pCommandString);
if (!g_pServerLimits->CheckStringCommandLimits(self))
{
@@ -476,6 +486,10 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerExploitFixes, ConVar, (CModule module))
}
}
- ns_exploitfixes_log =
+ Cvar_ns_exploitfixes_log =
new ConVar("ns_exploitfixes_log", "1", FCVAR_GAMEDLL, "Whether to log whenever ExploitFixes.cpp blocks/corrects something");
+ Cvar_ns_should_log_all_clientcommands =
+ new ConVar("ns_should_log_all_clientcommands", "0", FCVAR_NONE, "Whether to log all clientcommands");
+
+ Cvar_sv_cheats = R2::g_pCVar->FindVar("sv_cheats");
}
diff --git a/NorthstarDLL/masterserver.cpp b/NorthstarDLL/masterserver.cpp
index 75f0bb4b..b83170b0 100644
--- a/NorthstarDLL/masterserver.cpp
+++ b/NorthstarDLL/masterserver.cpp
@@ -485,6 +485,12 @@ void MasterServerManager::AuthenticateWithOwnServer(const char* uid, const char*
{
spdlog::error("Failed reading masterserver response: got fastify error response");
spdlog::error(readBuffer);
+
+ if (authInfoJson["error"].HasMember("enum"))
+ m_sAuthFailureReason = authInfoJson["error"]["enum"].GetString();
+ else
+ m_sAuthFailureReason = "No error message provided";
+
goto REQUEST_END_CLEANUP;
}
@@ -631,6 +637,12 @@ void MasterServerManager::AuthenticateWithServer(const char* uid, const char* pl
{
spdlog::error("Failed reading masterserver response: got fastify error response");
spdlog::error(readBuffer);
+
+ if (connectionInfoJson["error"].HasMember("enum"))
+ m_sAuthFailureReason = connectionInfoJson["error"]["enum"].GetString();
+ else
+ m_sAuthFailureReason = "No error message provided";
+
goto REQUEST_END_CLEANUP;
}
@@ -738,16 +750,27 @@ void MasterServerManager::WritePlayerPersistentData(const char* playerId, const
class MasterServerPresenceReporter : public ServerPresenceReporter
{
+ const int MAX_REGISTRATION_ATTEMPTS = 5;
+
+ double m_bShouldTryRegisterServer;
+ int m_nNumRegistrationAttempts;
+
+ void CreatePresence(const ServerPresence* pServerPresence) override
+ {
+ m_bShouldTryRegisterServer = true;
+ m_nNumRegistrationAttempts = 0;
+ }
+
void ReportPresence(const ServerPresence* pServerPresence) override
{
// make a copy of presence for multithreading purposes
ServerPresence threadedPresence(pServerPresence);
- if (!*g_pMasterServerManager->m_sOwnServerId)
+ if (!*g_pMasterServerManager->m_sOwnServerId || m_bShouldTryRegisterServer)
{
// add server
std::thread addServerThread(
- [threadedPresence]
+ [this, threadedPresence]
{
g_pMasterServerManager->m_sOwnServerId[0] = 0;
g_pMasterServerManager->m_sOwnServerAuthToken[0] = 0;
@@ -830,7 +853,14 @@ class MasterServerPresenceReporter : public ServerPresenceReporter
{
spdlog::error("Failed reading masterserver response: got fastify error response");
spdlog::error(readBuffer);
- goto REQUEST_END_CLEANUP;
+
+ if (serverAddedJson["error"].HasMember("enum") && !strcmp(serverAddedJson["error"]["enum"].GetString(), "DUPLICATE_SERVER"))
+ {
+ if (++m_nNumRegistrationAttempts == MAX_REGISTRATION_ATTEMPTS)
+ m_bShouldTryRegisterServer = false;
+ }
+
+ goto REQUEST_END_CLEANUP_RETRY;
}
if (!serverAddedJson["success"].IsTrue())
@@ -865,6 +895,9 @@ class MasterServerPresenceReporter : public ServerPresenceReporter
}
REQUEST_END_CLEANUP:
+ m_bShouldTryRegisterServer = false;
+
+ REQUEST_END_CLEANUP_RETRY:
curl_easy_cleanup(curl);
curl_mime_free(mime);
});
diff --git a/NorthstarDLL/masterserver.h b/NorthstarDLL/masterserver.h
index 856adaac..efa938cc 100644
--- a/NorthstarDLL/masterserver.h
+++ b/NorthstarDLL/masterserver.h
@@ -100,6 +100,7 @@ class MasterServerManager
bool m_bNewgameAfterSelfAuth = false;
bool m_bScriptAuthenticatingWithGameServer = false;
bool m_bSuccessfullyAuthenticatedWithGameServer = false;
+ std::string m_sAuthFailureReason {};
bool m_bHasPendingConnectionInfo = false;
RemoteServerConnectionInfo m_pendingConnectionInfo;
diff --git a/NorthstarDLL/printcommands.cpp b/NorthstarDLL/printcommands.cpp
index 8acf6262..605f7dce 100644
--- a/NorthstarDLL/printcommands.cpp
+++ b/NorthstarDLL/printcommands.cpp
@@ -145,7 +145,7 @@ void ConCommand_findflags(const CCommand& arg)
{
if (!strcmp(flagPair.second, upperFlag))
{
- resolvedFlag = flagPair.first;
+ resolvedFlag |= flagPair.first;
break;
}
}
diff --git a/NorthstarDLL/printmaps.cpp b/NorthstarDLL/printmaps.cpp
index 4aa28f3e..7a12b1fe 100644
--- a/NorthstarDLL/printmaps.cpp
+++ b/NorthstarDLL/printmaps.cpp
@@ -98,7 +98,7 @@ void RefreshMapList()
}
// get maps in game dir
- for (fs::directory_entry file : fs::directory_iterator(fmt::format("{}/maps", "r2")))
+ for (fs::directory_entry file : fs::directory_iterator(fmt::format("{}/maps", R2::g_pModName)))
{
if (file.path().extension() == ".bsp")
{
diff --git a/NorthstarDLL/r2engine.cpp b/NorthstarDLL/r2engine.cpp
index a3b6225f..5a5568c1 100644
--- a/NorthstarDLL/r2engine.cpp
+++ b/NorthstarDLL/r2engine.cpp
@@ -16,6 +16,8 @@ namespace R2
CBaseClient* g_pClientArray;
server_state_t* g_pServerState;
+
+ char* g_pModName = nullptr; // we cant set this up here atm since we dont have an offset to it in engine, instead we store it in IsRespawnMod
} // namespace R2
ON_DLL_LOAD("engine.dll", R2Engine, (CModule module))
diff --git a/NorthstarDLL/r2engine.h b/NorthstarDLL/r2engine.h
index 717c1799..e5755c54 100644
--- a/NorthstarDLL/r2engine.h
+++ b/NorthstarDLL/r2engine.h
@@ -194,4 +194,6 @@ namespace R2
};
extern server_state_t* g_pServerState;
+
+ extern char* g_pModName;
} // namespace R2
diff --git a/NorthstarDLL/rpakfilesystem.cpp b/NorthstarDLL/rpakfilesystem.cpp
index 7ab1b723..46e0e725 100644
--- a/NorthstarDLL/rpakfilesystem.cpp
+++ b/NorthstarDLL/rpakfilesystem.cpp
@@ -2,6 +2,7 @@
#include "rpakfilesystem.h"
#include "modmanager.h"
#include "dedicated.h"
+#include "tier0.h"
AUTOHOOK_INIT()
@@ -14,7 +15,7 @@ struct PakLoadFuncs
void* unk1[2];
void* (*UnloadPak)(int iPakHandle, void* callback);
void* unk2[17];
- void* (*ReadFullFileFromDisk)(const char* pPath, void* a2);
+ void* (*ReadFileAsync)(const char* pPath, void* a2);
};
PakLoadFuncs* g_pakLoadApi;
@@ -136,7 +137,7 @@ int,, (char* pPath, void* unknownSingleton, int flags, void* callback0, void* ca
// do this after custom paks load and in bShouldLoadPaks so we only ever call this on the root pakload call
// todo: could probably add some way to flag custom paks to not be loaded on dedicated servers in rpak.json
- if (IsDedicatedServer() && strncmp(&originalPath[0], "common", 6)) // dedicated only needs common and common_mp
+ if (IsDedicatedServer() && (Tier0::CommandLine()->CheckParm("-nopakdedi") || strncmp(&originalPath[0], "common", 6))) // dedicated only needs common and common_mp
{
spdlog::info("Not loading pak {} for dedicated server", originalPath);
return -1;
@@ -170,7 +171,7 @@ void*,, (int iPakHandle, void* callback))
// we hook this exclusively for resolving stbsp paths, but seemingly it's also used for other stuff like vpk and rpak loads
// possibly just async loading altogether?
-HOOK(ReadFullFileFromDiskHook, ReadFullFileFromDisk,
+HOOK(ReadFileAsyncHook, ReadFileAsync,
void*, , (const char* pPath, void* a2))
{
fs::path path(pPath);
@@ -182,7 +183,6 @@ void*, , (const char* pPath, void* a2))
spdlog::info("LoadStreamBsp: {}", filename.string());
// resolve modded stbsp path so we can load mod stbsps
-
auto modFile = g_pModManager->m_ModFiles.find(g_pModManager->NormaliseModFilePath(fs::path("maps" / filename)));
if (modFile != g_pModManager->m_ModFiles.end())
{
@@ -194,7 +194,9 @@ void*, , (const char* pPath, void* a2))
}
}
- void* ret = ReadFullFileFromDisk(pPath, a2);
+ // this is used for reading vpk, rpak, starpak, stbsp, and mprj also
+
+ void* ret = ReadFileAsync(pPath, a2);
if (allocatedNewPath)
delete[] allocatedNewPath;
@@ -213,5 +215,5 @@ ON_DLL_LOAD("engine.dll", RpakFilesystem, (CModule module))
LoadPakAsyncHook.Dispatch(g_pakLoadApi->LoadPakAsync);
UnloadPakHook.Dispatch(g_pakLoadApi->UnloadPak);
- ReadFullFileFromDiskHook.Dispatch(g_pakLoadApi->ReadFullFileFromDisk);
+ ReadFileAsyncHook.Dispatch(g_pakLoadApi->ReadFileAsync);
}
diff --git a/NorthstarDLL/scriptserverbrowser.cpp b/NorthstarDLL/scriptserverbrowser.cpp
index bdc49303..0e647f45 100644
--- a/NorthstarDLL/scriptserverbrowser.cpp
+++ b/NorthstarDLL/scriptserverbrowser.cpp
@@ -409,6 +409,13 @@ SQRESULT SQ_CompleteAuthWithLocalServer(void* sqvm)
return SQRESULT_NULL;
}
+// string function NSGetAuthFailReason()
+SQRESULT SQ_GetAuthFailReason(void* sqvm)
+{
+ g_pSquirrel<ScriptContext::UI>->pushstring(sqvm, g_pMasterServerManager->m_sAuthFailureReason.c_str(), -1);
+ return SQRESULT_NOTNULL;
+}
+
ON_DLL_LOAD_CLIENT_RELIESON("client.dll", ScriptServerBrowser, ClientSquirrel, (CModule module))
{
g_pSquirrel<ScriptContext::UI>->AddFuncRegistration("bool", "NSIsMasterServerAuthenticated", "", "", SQ_IsMasterServerAuthenticated);
@@ -440,4 +447,6 @@ ON_DLL_LOAD_CLIENT_RELIESON("client.dll", ScriptServerBrowser, ClientSquirrel, (
g_pSquirrel<ScriptContext::UI>->AddFuncRegistration("void", "NSTryAuthWithLocalServer", "", "", SQ_TryAuthWithLocalServer);
g_pSquirrel<ScriptContext::UI>->AddFuncRegistration("void", "NSCompleteAuthWithLocalServer", "", "", SQ_CompleteAuthWithLocalServer);
+
+ g_pSquirrel<ScriptContext::UI>->AddFuncRegistration("string", "NSGetAuthFailReason", "", "", SQ_GetAuthFailReason);
}
diff --git a/NorthstarDLL/serverpresence.cpp b/NorthstarDLL/serverpresence.cpp
index 4e9c5c28..cfc1c213 100644
--- a/NorthstarDLL/serverpresence.cpp
+++ b/NorthstarDLL/serverpresence.cpp
@@ -117,6 +117,7 @@ void ServerPresenceManager::CreatePresence()
m_ServerPresence.m_bIsSingleplayerServer = false;
m_bHasPresence = true;
+ m_bFirstPresenceUpdate = true;
// code that's calling this should set up the reset fields at this point
}
@@ -142,6 +143,16 @@ void ServerPresenceManager::RunFrame(double flCurrentTime)
if ((flCurrentTime - m_flLastPresenceUpdate) * 1000 < Cvar_ns_server_presence_update_rate->GetFloat())
return;
+ // is this the first frame we're updating this presence?
+ if (m_bFirstPresenceUpdate)
+ {
+ // let reporters setup/clear any state
+ for (ServerPresenceReporter* reporter : m_vPresenceReporters)
+ reporter->CreatePresence(&m_ServerPresence);
+
+ m_bFirstPresenceUpdate = false;
+ }
+
m_flLastPresenceUpdate = flCurrentTime;
for (ServerPresenceReporter* reporter : m_vPresenceReporters)
@@ -178,7 +189,7 @@ void ServerPresenceManager::SetPassword(const char* pPassword)
strncpy_s(m_ServerPresence.m_Password, sizeof(m_ServerPresence.m_Password), pPassword, sizeof(m_ServerPresence.m_Password) - 1);
}
-void ServerPresenceManager::SetMap(const char* pMapName, bool isInitialising = false)
+void ServerPresenceManager::SetMap(const char* pMapName, bool isInitialising)
{
// if the server is initialising (i.e. this is first map) on sp, set the server to sp
if (isInitialising)
diff --git a/NorthstarDLL/serverpresence.h b/NorthstarDLL/serverpresence.h
index 018cd862..f27c9393 100644
--- a/NorthstarDLL/serverpresence.h
+++ b/NorthstarDLL/serverpresence.h
@@ -42,6 +42,7 @@ struct ServerPresence
class ServerPresenceReporter
{
public:
+ virtual void CreatePresence(const ServerPresence* pServerPresence) {}
virtual void ReportPresence(const ServerPresence* pServerPresence) {}
virtual void DestroyPresence(const ServerPresence* pServerPresence) {}
};
@@ -52,6 +53,7 @@ class ServerPresenceManager
ServerPresence m_ServerPresence;
bool m_bHasPresence = false;
+ bool m_bFirstPresenceUpdate = false;
std::vector<ServerPresenceReporter*> m_vPresenceReporters;
diff --git a/NorthstarDLL/squirrel.cpp b/NorthstarDLL/squirrel.cpp
index e5f29ee6..bede510e 100644
--- a/NorthstarDLL/squirrel.cpp
+++ b/NorthstarDLL/squirrel.cpp
@@ -25,7 +25,7 @@ template <ScriptContext context> void* (*sq_compiler_create)(void* sqvm, void* a
template <ScriptContext context> void* sq_compiler_createHook(void* sqvm, void* a2, void* a3, SQBool bShouldThrowError)
{
// store whether errors generated from this compile should be fatal
- if (sqvm == g_pSquirrel<ScriptContext::UI>->sqvm2)
+ if (context == ScriptContext::CLIENT && sqvm == g_pSquirrel<ScriptContext::UI>->sqvm2)
g_pSquirrel<ScriptContext::UI>->m_bCompilationErrorsFatal = bShouldThrowError;
else
g_pSquirrel<context>->m_bCompilationErrorsFatal = bShouldThrowError;
@@ -71,7 +71,7 @@ template <ScriptContext context> void (*DestroyVM)(void* a1, void* sqvm);
template <ScriptContext context> void DestroyVMHook(void* a1, void* sqvm)
{
ScriptContext realContext = context; // ui and client use the same function so we use this for prints
- if (sqvm == g_pSquirrel<ScriptContext::UI>->sqvm)
+ if (context == ScriptContext::CLIENT && sqvm == g_pSquirrel<ScriptContext::UI>->sqvm)
{
realContext = ScriptContext::UI;
g_pSquirrel<ScriptContext::UI>->VMDestroyed();
@@ -87,7 +87,7 @@ template <ScriptContext context> void ScriptCompileErrorHook(void* sqvm, const c
{
bool bIsFatalError = g_pSquirrel<context>->m_bCompilationErrorsFatal;
ScriptContext realContext = context; // ui and client use the same function so we use this for prints
- if (sqvm == g_pSquirrel<ScriptContext::UI>->sqvm2)
+ if (context == ScriptContext::CLIENT && sqvm == g_pSquirrel<ScriptContext::UI>->sqvm2)
{
realContext = ScriptContext::UI;
bIsFatalError = g_pSquirrel<ScriptContext::UI>->m_bCompilationErrorsFatal;