diff --git a/src/game/client/DelayLoad.cpp b/src/game/client/DelayLoad.cpp index 4e2a49018..0c5689931 100644 --- a/src/game/client/DelayLoad.cpp +++ b/src/game/client/DelayLoad.cpp @@ -26,7 +26,7 @@ FARPROC DelayLoad_LoadGameLib(const char* dllName) { ASSERT(dllName); - const auto gameDir = FileSystem_GetGameDirectory(); + const auto& gameDir = FileSystem_GetModDirectoryName(); const auto path = fmt::format("{}/{}", gameDir, dllName); diff --git a/src/game/client/cdll_int.cpp b/src/game/client/cdll_int.cpp index ee9a4658b..1fb38cb9d 100644 --- a/src/game/client/cdll_int.cpp +++ b/src/game/client/cdll_int.cpp @@ -18,6 +18,8 @@ // this implementation handles the linking of the engine to the DLL // +#include + #include "hud.h" #include "utils/shared_utils.h" #include "netadr.h" @@ -93,6 +95,30 @@ void DLLEXPORT HUD_PlayerMove(playermove_t* ppmove, int server) PM_Move(ppmove, server); } +static bool CL_InitClient() +{ + HUD_SetupServerEngineInterface(); + + EV_HookEvents(); + CL_LoadParticleMan(); + + if (!FileSystem_LoadFileSystem()) + { + return false; + } + + if (UTIL_IsValveGameDirectory()) + { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", + "This mod has detected that it is being run from a Valve game directory which is not supported\n" + "Run this mod from its intended location\n\nThe game will now shut down", nullptr); + return false; + } + + // get tracker interface, if any + return true; +} + int DLLEXPORT Initialize(cl_enginefunc_t* pEnginefuncs, int iVersion) { gEngfuncs = *pEnginefuncs; @@ -102,17 +128,15 @@ int DLLEXPORT Initialize(cl_enginefunc_t* pEnginefuncs, int iVersion) memcpy(&gEngfuncs, pEnginefuncs, sizeof(cl_enginefunc_t)); - HUD_SetupServerEngineInterface(); + const bool result = CL_InitClient() && g_Client.Initialize(); - EV_HookEvents(); - CL_LoadParticleMan(); - - if (!g_Client.Initialize()) + if (!result) { + gEngfuncs.Con_DPrintf("Error initializing client\n"); + gEngfuncs.pfnClientCmd("quit\n"); return 0; } - // get tracker interface, if any return 1; } diff --git a/src/game/server/game.cpp b/src/game/server/game.cpp index 4da1e4b51..d48a45cda 100644 --- a/src/game/server/game.cpp +++ b/src/game/server/game.cpp @@ -55,6 +55,28 @@ cvar_t sv_entityinfo_eager{"sv_entityinfo_eager", "1", FCVAR_SERVER}; cvar_t sv_schedule_debug{"sv_schedule_debug", "0", FCVAR_SERVER}; +static bool SV_InitServer() +{ + if (!FileSystem_LoadFileSystem()) + { + return false; + } + + if (UTIL_IsValveGameDirectory()) + { + g_engfuncs.pfnServerPrint("This mod has detected that it is being run from a Valve game directory which is not supported\n" + "Run this mod from its intended location\n\nThe game will now shut down\n"); + return false; + } + + if (!g_Server.Initialize()) + { + return false; + } + + return true; +} + // Register your console variables here // This gets called one time when the game is initialied void GameDLLInit() @@ -66,6 +88,14 @@ void GameDLLInit() g_footsteps = CVAR_GET_POINTER("mp_footsteps"); g_psv_cheats = CVAR_GET_POINTER("sv_cheats"); + if (!SV_InitServer()) + { + g_engfuncs.pfnServerPrint("Error initializing server\n"); + // Shut the game down as soon as possible. + SERVER_COMMAND("quit\n"); + return; + } + CVAR_REGISTER(&displaysoundlist); CVAR_REGISTER(&allow_spectators); @@ -110,13 +140,6 @@ void GameDLLInit() // Link user messages immediately so there are no race conditions. LinkUserMessages(); - - if (!g_Server.Initialize()) - { - // Shut the game down ASAP - SERVER_COMMAND("quit\n"); - return; - } } void GameDLLShutdown() diff --git a/src/game/shared/utils/LogSystem.cpp b/src/game/shared/utils/LogSystem.cpp index 9e4daf7ca..819675d10 100644 --- a/src/game/shared/utils/LogSystem.cpp +++ b/src/game/shared/utils/LogSystem.cpp @@ -405,7 +405,7 @@ void LogSystem::SetFileLoggingEnabled(bool enable) if (enable && !m_FileSink) { // Separate log files into client and server files to avoid races between the two. - const std::string gameDir = FileSystem_GetGameDirectory(); + const std::string& gameDir = FileSystem_GetModDirectoryName(); const std::string baseFileName = fmt::format("{}/logs/{}/{}.log", gameDir, GetShortLibraryPrefix(), m_Settings.LogFile.BaseFileName.value_or(DefaultBaseFileName)); diff --git a/src/game/shared/utils/filesystem_utils.cpp b/src/game/shared/utils/filesystem_utils.cpp index be0b1637e..6390e87a7 100644 --- a/src/game/shared/utils/filesystem_utils.cpp +++ b/src/game/shared/utils/filesystem_utils.cpp @@ -52,6 +52,7 @@ static CSysModule* g_pFileSystemModule = nullptr; // The engine's filesystem doesn't provide functions to do this so we have to work around it. static std::string g_GameDirectory; static std::string g_ModDirectory; +static std::string g_ModDirectoryName; static bool FileSystem_InitializeGameDirectory() { @@ -96,18 +97,17 @@ static bool FileSystem_InitializeGameDirectory() gameDirectory.shrink_to_fit(); - std::string modDirectory; - modDirectory.resize(BufferSize); + g_ModDirectoryName.resize(BufferSize); #ifdef CLIENT_DLL - modDirectory = gEngfuncs.pfnGetGameDirectory(); + g_ModDirectoryName = gEngfuncs.pfnGetGameDirectory(); #else - g_engfuncs.pfnGetGameDir(modDirectory.data()); - modDirectory.resize(std::strlen(modDirectory.c_str())); + g_engfuncs.pfnGetGameDir(g_ModDirectoryName.data()); + g_ModDirectoryName.resize(std::strlen(g_ModDirectoryName.c_str())); #endif g_GameDirectory = std::move(gameDirectory); - g_ModDirectory = g_GameDirectory + DefaultPathSeparatorChar + modDirectory; + g_ModDirectory = g_GameDirectory + DefaultPathSeparatorChar + g_ModDirectoryName; return true; } @@ -180,17 +180,9 @@ void FileSystem_FreeFileSystem() } } -std::string FileSystem_GetGameDirectory() +const std::string& FileSystem_GetModDirectoryName() { -#ifdef CLIENT_DLL - return gEngfuncs.pfnGetGameDirectory(); -#else - char gameDir[MAX_PATH_LENGTH]; - g_engfuncs.pfnGetGameDir(gameDir); - gameDir[sizeof(gameDir) - 1] = '\0'; - - return gameDir; -#endif + return g_ModDirectoryName; } void FileSystem_FixSlashes(std::string& fileName) @@ -339,3 +331,30 @@ bool FileSystem_WriteTextToFile(const char* fileName, const char* text, const ch return false; } + +constexpr const char* ValveGameDirectoryPrefixes[] = + { + "valve", + "gearbox", + "bshift", + "ricochet", + "dmc", + "cstrike", + "czero", // Also covers Deleted Scenes (czeror) + "dod", + "tfc"}; + +bool UTIL_IsValveGameDirectory() +{ + const std::string& modDirectoryName = FileSystem_GetModDirectoryName(); + + for (const auto prefix : ValveGameDirectoryPrefixes) + { + if (strnicmp(modDirectoryName.c_str(), prefix, strlen(prefix)) == 0) + { + return true; + } + } + + return false; +} diff --git a/src/game/shared/utils/filesystem_utils.h b/src/game/shared/utils/filesystem_utils.h index 9a1a04c5a..c00afcf7e 100644 --- a/src/game/shared/utils/filesystem_utils.h +++ b/src/game/shared/utils/filesystem_utils.h @@ -44,7 +44,10 @@ inline IFileSystem* g_pFileSystem = nullptr; bool FileSystem_LoadFileSystem(); void FileSystem_FreeFileSystem(); -std::string FileSystem_GetGameDirectory(); +/** + * @brief Returns the mod directory name. Only valid to call after calling FileSystem_LoadFileSystem. + */ +const std::string& FileSystem_GetModDirectoryName(); /** * @brief Replaces occurrences of ::AlternatePathSeparatorChar with ::DefaultPathSeparatorChar. @@ -104,6 +107,12 @@ std::vector FileSystem_LoadFileIntoBuffer(const char* fileName, FileC */ bool FileSystem_WriteTextToFile(const char* fileName, const char* text, const char* pathID = nullptr); +/** + * @brief Returns @c true if the current game directory is that of a Valve game. + * Any directory whose name starts with that of a Valve game's directory name is considered to be one, matching Steam's behavior. + */ +bool UTIL_IsValveGameDirectory(); + /** * @brief Helper class to automatically close the file handle associated with a file. */