diff --git a/Client/core/CConsole.cpp b/Client/core/CConsole.cpp index 340187f1d84..ce372e792d3 100644 --- a/Client/core/CConsole.cpp +++ b/Client/core/CConsole.cpp @@ -51,8 +51,13 @@ CConsole::CConsole(CGUI* pManager, CGUIElement* pParent) m_pHistory->SetTextChangedHandler(GUI_CALLBACK(&CConsole::History_OnTextChanged, this)); - // Load the console history from a file - m_pConsoleHistory->LoadFromFile(MTA_CONSOLE_INPUT_LOG_PATH); + // Load the console history from a file - use -cl2 suffix for secondary client + SString strInputLogPath = MTA_CONSOLE_INPUT_LOG_PATH; + if (g_pCore->IsSecondaryClient()) + { + strInputLogPath.Replace(".log", "-cl2.log"); + } + m_pConsoleHistory->LoadFromFile(strInputLogPath); } CConsole::~CConsole() diff --git a/Client/core/CConsoleLogger.cpp b/Client/core/CConsoleLogger.cpp index b4a9e65eec0..8f1535bb037 100644 --- a/Client/core/CConsoleLogger.cpp +++ b/Client/core/CConsoleLogger.cpp @@ -19,8 +19,13 @@ CConsoleLogger* CSingleton::m_pSingleton = NULL; CConsoleLogger::CConsoleLogger() { - // Create file name - m_strFilename = CalcMTASAPath(MTA_CONSOLE_LOG_PATH); + // Create file name - use -cl2 suffix for secondary client + SString strLogPath = MTA_CONSOLE_LOG_PATH; + if (g_pCore->IsSecondaryClient()) + { + strLogPath.Replace(".log", "-cl2.log"); + } + m_strFilename = CalcMTASAPath(strLogPath); // Cycle if over size (100KB, 5 backup files) CycleFile(m_strFilename, 100, 5); diff --git a/Client/core/CCore.cpp b/Client/core/CCore.cpp index 355b2842756..ec8016e4f05 100644 --- a/Client/core/CCore.cpp +++ b/Client/core/CCore.cpp @@ -727,6 +727,20 @@ const char* CCore::GetModInstallRoot(const char* szModName) return m_strModInstallRoot; } +bool CCore::IsSecondaryClient() +{ + static bool bChecked = false; + static bool bIsSecondary = false; + + if (!bChecked) + { + bIsSecondary = (strstr(GetCommandLine(), "-cl2") != NULL); + bChecked = true; + } + + return bIsSecondary; +} + void CCore::ForceCursorVisible(bool bVisible, bool bToggleControls) { m_bCursorToggleControls = bToggleControls; @@ -870,6 +884,23 @@ void CCore::ApplyHooks() // Remove useless DirectPlay dependency (dpnhpast.dll) @ 0x745701 // We have to patch here as multiplayer_sa and game_sa are loaded too late DetourLibraryFunction("kernel32.dll", "LoadLibraryA", Win32LoadLibraryA, SkipDirectPlay_LoadLibraryA); + + // Special thanks for botder too [https://github.com/multitheftauto/mtasa-blue/commit/b08948fcf46746c9d74503a0889996575f93cde5] + // Disable code that disallows multiple instances of GTA:SA + // Disable `if (IsAppAlreadyRunning())` in WinMain + { + DWORD oldProtect; + VirtualProtect(reinterpret_cast(0x74872D), 9, PAGE_READWRITE, &oldProtect); + memcpy(reinterpret_cast(0x74872D), "\x90\x90\x90\x90\x90\x90\x90\x90\x90", 9); + VirtualProtect(reinterpret_cast(0x74872D), 9, oldProtect, &oldProtect); + } + // Create an unnamed semaphore in CdStreamInitThread. + { + DWORD oldProtect; + VirtualProtect(reinterpret_cast(0x406945), 5, PAGE_READWRITE, &oldProtect); + memcpy(reinterpret_cast(0x406945), "\x6A\x00\x90\x90\x90", 5); + VirtualProtect(reinterpret_cast(0x406945), 5, oldProtect, &oldProtect); + } } bool UsingAltD3DSetup() @@ -1093,8 +1124,27 @@ void CCore::CreateXML() if (!m_pConfigFile) { - // Load config XML file - m_pConfigFile = m_pXML->CreateXML(CalcMTASAPath(MTA_CONFIG_PATH)); + // Load config XML file - use -cl2 suffix for secondary client + SString strConfigPath = MTA_CONFIG_PATH; + bool bIsSecondary = IsSecondaryClient(); + + if (bIsSecondary) + { + strConfigPath = strConfigPath.Replace(".xml", "-cl2.xml"); + + // If CL2 config doesn't exist, copy from the primary config + SString strFullPath = CalcMTASAPath(strConfigPath); + if (!FileExists(strFullPath)) + { + SString strPrimaryConfig = CalcMTASAPath(MTA_CONFIG_PATH); + if (FileExists(strPrimaryConfig)) + { + FileCopy(strPrimaryConfig, strFullPath); + } + } + } + + m_pConfigFile = m_pXML->CreateXML(CalcMTASAPath(strConfigPath)); if (!m_pConfigFile) { assert(false); diff --git a/Client/core/CCore.h b/Client/core/CCore.h index 2e5d650b1b6..8118e209d57 100644 --- a/Client/core/CCore.h +++ b/Client/core/CCore.h @@ -174,6 +174,7 @@ class CCore : public CCoreInterface, public CSingleton bool IsOfflineMod() { return m_bIsOfflineMod; } const char* GetModInstallRoot(const char* szModName); bool CheckDiskSpace(uint uiResourcesPathMinMB = 10, uint uiDataPathMinMB = 10); + bool IsSecondaryClient(); // Subsystems void CreateGame(); diff --git a/Client/core/CSettings.cpp b/Client/core/CSettings.cpp index f35f9e39a35..63403f7429c 100644 --- a/Client/core/CSettings.cpp +++ b/Client/core/CSettings.cpp @@ -4964,7 +4964,26 @@ void CSettings::SetChatColorValues(eChatColorType eType, CColor pColor) void CSettings::LoadChatPresets() { - CXMLFile* pPresetsFile = CCore::GetSingleton().GetXML()->CreateXML(CalcMTASAPath(CHAT_PRESETS_PATH)); + SString strPresetsPath = CHAT_PRESETS_PATH; + bool bIsSecondary = g_pCore->IsSecondaryClient(); + + if (bIsSecondary) + { + strPresetsPath = strPresetsPath.Replace(".xml", "-cl2.xml"); + + // If CL2 presets file doesn't exist, copy from the primary + SString strFullPath = CalcMTASAPath(strPresetsPath); + if (!FileExists(strFullPath)) + { + SString strPrimaryPresets = CalcMTASAPath(CHAT_PRESETS_PATH); + if (FileExists(strPrimaryPresets)) + { + FileCopy(strPrimaryPresets, strFullPath); + } + } + } + + CXMLFile* pPresetsFile = CCore::GetSingleton().GetXML()->CreateXML(CalcMTASAPath(strPresetsPath)); if (pPresetsFile && pPresetsFile->Parse()) { CXMLNode* pPresetsRoot = pPresetsFile->GetRootNode(); diff --git a/Client/core/CVersionUpdater.cpp b/Client/core/CVersionUpdater.cpp index cde550d4982..c560f4087c9 100644 --- a/Client/core/CVersionUpdater.cpp +++ b/Client/core/CVersionUpdater.cpp @@ -564,6 +564,18 @@ void CVersionUpdater::DoPulse() /////////////////////////////////////////////////////////////// void CVersionUpdater::InitiateUpdate(const SString& strType, const SString& strData, const SString& strHost) { + // Disable server-initiated updates for secondary client + if (CCore::GetSingleton().IsSecondaryClient()) + return; + + // Don't allow update if CL2 is running + HANDLE hCL2Mutex = OpenMutexA(SYNCHRONIZE, FALSE, "Global\\{4962AF5F-5D82-412D-9CCA-AB8BB9DBD354}"); + if (hCL2Mutex) + { + CloseHandle(hCL2Mutex); + return; + } + if (strType == "Mandatory") { CCore::GetSingleton().RemoveMessageBox(); @@ -615,6 +627,22 @@ void CVersionUpdater::InitiateDataFilesFix() /////////////////////////////////////////////////////////////// void CVersionUpdater::InitiateManualCheck() { + // Disable update checking for secondary client + if (CCore::GetSingleton().IsSecondaryClient()) + { + CCore::GetSingleton().ShowMessageBox(_("Information"), _("Update checking is disabled in secondary client"), MB_BUTTON_OK | MB_ICON_INFO); + return; + } + + // Don't allow update if CL2 is running + HANDLE hCL2Mutex = OpenMutexA(SYNCHRONIZE, FALSE, "Global\\{4962AF5F-5D82-412D-9CCA-AB8BB9DBD354}"); + if (hCL2Mutex) + { + CloseHandle(hCL2Mutex); + CCore::GetSingleton().ShowMessageBox(_("Information"), _("Can't check for updates while secondary client is running"), MB_BUTTON_OK | MB_ICON_INFO); + return; + } + if (GetQuestionBox().IsVisible()) { // Bring to the front diff --git a/Client/core/DXHook/CProxyDirect3D9.cpp b/Client/core/DXHook/CProxyDirect3D9.cpp index 31391ba020e..9b2676ce12d 100644 --- a/Client/core/DXHook/CProxyDirect3D9.cpp +++ b/Client/core/DXHook/CProxyDirect3D9.cpp @@ -326,10 +326,11 @@ HRESULT CProxyDirect3D9::CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND pPresentationParameters->PresentationInterval)); // Change the window title to MTA: San Andreas + bool bIsSecondaryClient = g_pCore->IsSecondaryClient(); #ifdef MTA_DEBUG - SetWindowTextW(hFocusWindow, MbUTF8ToUTF16("MTA: San Andreas [DEBUG]").c_str()); + SetWindowTextW(hFocusWindow, MbUTF8ToUTF16(bIsSecondaryClient ? "MTA: San Andreas [CL2-DEBUG]" : "MTA: San Andreas [DEBUG]").c_str()); #else - SetWindowTextW(hFocusWindow, MbUTF8ToUTF16("MTA: San Andreas").c_str()); + SetWindowTextW(hFocusWindow, MbUTF8ToUTF16(bIsSecondaryClient ? "MTA: San Andreas [CL2]" : "MTA: San Andreas").c_str()); #endif // Set dark titlebar if needed @@ -1348,10 +1349,11 @@ HRESULT CCore::OnPostCreateDevice(HRESULT hResult, IDirect3D9* pDirect3D, UINT A AddCapsReport(Adapter, pDirect3D, *ppReturnedDeviceInterface, true); // Change the window title to MTA: San Andreas + bool bIsSecondaryClient = g_pCore->IsSecondaryClient(); #ifdef MTA_DEBUG - SetWindowTextW(hFocusWindow, MbUTF8ToUTF16("MTA: San Andreas [DEBUG]").c_str()); + SetWindowTextW(hFocusWindow, MbUTF8ToUTF16(bIsSecondaryClient ? "MTA: San Andreas [CL2-DEBUG]" : "MTA: San Andreas [DEBUG]").c_str()); #else - SetWindowTextW(hFocusWindow, MbUTF8ToUTF16("MTA: San Andreas").c_str()); + SetWindowTextW(hFocusWindow, MbUTF8ToUTF16(bIsSecondaryClient ? "MTA: San Andreas [CL2]" : "MTA: San Andreas").c_str()); #endif // Log graphic card name diff --git a/Client/core/ServerBrowser/CServerCache.cpp b/Client/core/ServerBrowser/CServerCache.cpp index d3f8bba3270..feef538ae47 100644 --- a/Client/core/ServerBrowser/CServerCache.cpp +++ b/Client/core/ServerBrowser/CServerCache.cpp @@ -126,8 +126,25 @@ CServerCache::~CServerCache() /////////////////////////////////////////////////////////////// bool CServerCache::LoadServerCache() { - // Load config XML file - CXMLFile* m_pConfigFile = CCore::GetSingleton().GetXML()->CreateXML(CalcMTASAPath(MTA_SERVER_CACHE_PATH)); + // Load config XML file - use -cl2 suffix for secondary client + SString strCachePath = MTA_SERVER_CACHE_PATH; + if (g_pCore->IsSecondaryClient()) + { + strCachePath = strCachePath.Replace(".xml", "-cl2.xml"); + + // If CL2 cache doesn't exist, copy from the primary cache + SString strFullPath = CalcMTASAPath(strCachePath); + if (!FileExists(strFullPath)) + { + SString strPrimaryCache = CalcMTASAPath(MTA_SERVER_CACHE_PATH); + if (FileExists(strPrimaryCache)) + { + FileCopy(strPrimaryCache, strFullPath); + } + } + } + + CXMLFile* m_pConfigFile = CCore::GetSingleton().GetXML()->CreateXML(CalcMTASAPath(strCachePath)); if (!m_pConfigFile) return false; m_pConfigFile->Parse(); @@ -269,7 +286,14 @@ DWORD WINAPI CServerCache::StaticThreadProc(LPVOID lpdwThreadParam) /////////////////////////////////////////////////////////////// void CServerCache::StaticSaveServerCache() { - CXMLFile* m_pConfigFile = CCore::GetSingleton().GetXML()->CreateXML(CalcMTASAPath(MTA_SERVER_CACHE_PATH)); + // Use -cl2 suffix for secondary client + SString strCachePath = MTA_SERVER_CACHE_PATH; + if (g_pCore->IsSecondaryClient()) + { + strCachePath = strCachePath.Replace(".xml", "-cl2.xml"); + } + + CXMLFile* m_pConfigFile = CCore::GetSingleton().GetXML()->CreateXML(CalcMTASAPath(strCachePath)); if (!m_pConfigFile) return; m_pConfigFile->Parse(); diff --git a/Client/loader/Main.h b/Client/loader/Main.h index a24661b3f52..7aa31a429cc 100644 --- a/Client/loader/Main.h +++ b/Client/loader/Main.h @@ -16,6 +16,7 @@ #define STEAM_GTA_EXE_NAME "gta-sa.exe" #define MTA_GTA_KNOWN_FILE_NAME "models\\gta3.img" #define MTA_GUID "Global\\{4962AF5F-5D82-412D-9CCA-AB8BB9DBD353}" +#define MTA_GUID_CL2 "Global\\{4962AF5F-5D82-412D-9CCA-AB8BB9DBD354}" #define URI_CONNECT 1 #define MTA_EXE_NAME_RELEASE "Multi Theft Auto.exe" #define LOADER_PROXY_DLL_NAME "mtasa.dll" diff --git a/Client/loader/MainFunctions.cpp b/Client/loader/MainFunctions.cpp index abd523dfc67..4ef176d59b6 100644 --- a/Client/loader/MainFunctions.cpp +++ b/Client/loader/MainFunctions.cpp @@ -441,7 +441,8 @@ void HandleNotUsedMainMenu() // Check current display mode in coreconfig.xml { - SString strCoreConfigFilename = CalcMTASAPath(PathJoin("mta", "config", "coreconfig.xml")); + SString strCoreConfigName = IsSecondaryClient() ? "coreconfig-cl2.xml" : "coreconfig.xml"; + SString strCoreConfigFilename = CalcMTASAPath(PathJoin("mta", "config", strCoreConfigName)); SString strCoreConfig; FileLoad(strCoreConfigFilename, strCoreConfig); SString strWindowed = strCoreConfig.SplitRight("").Left(1); @@ -707,6 +708,10 @@ void PostRunWatchDogs(int iReturnCode) ////////////////////////////////////////////////////////// void HandleIfGTAIsAlreadyRunning() { + // Skip GTA check for secondary client to allow multiple GTA instances + if (IsSecondaryClient()) + return; + if (IsGTARunning()) { if (MessageBoxUTF8(0, diff --git a/Client/loader/Utils.cpp b/Client/loader/Utils.cpp index b00b0ae6eaf..89f3f547f80 100644 --- a/Client/loader/Utils.cpp +++ b/Client/loader/Utils.cpp @@ -30,6 +30,17 @@ namespace fs = std::filesystem; static SString g_strMTASAPath; static SString g_strGTAPath; static HANDLE g_hMutex = NULL; + +// Check if secondary client mode is active +bool IsSecondaryClient() +{ + static int iResult = -1; + if (iResult == -1) + { + iResult = (strstr(GetCommandLine(), "-cl2") != NULL) ? 1 : 0; + } + return iResult == 1; +} static HMODULE hLibraryModule = NULL; HINSTANCE g_hInstance = NULL; @@ -321,6 +332,14 @@ std::vector GetGTAProcessList() /////////////////////////////////////////////////////////////////////////// bool IsGTARunning() { + // Don't report GTA as running if CL2 is active (to allow coexistence) + HANDLE hCL2Mutex = OpenMutexA(SYNCHRONIZE, FALSE, MTA_GUID_CL2); + if (hCL2Mutex) + { + CloseHandle(hCL2Mutex); + return false; + } + return !GetGTAProcessList().empty(); } @@ -333,6 +352,17 @@ bool IsGTARunning() /////////////////////////////////////////////////////////////////////////// void TerminateGTAIfRunning() { + if (IsSecondaryClient()) + return; + + // Don't terminate GTA if CL2 is running + HANDLE hCL2Mutex = OpenMutexA(SYNCHRONIZE, FALSE, MTA_GUID_CL2); + if (hCL2Mutex) + { + CloseHandle(hCL2Mutex); + return; + } + std::vector processIdList = GetGTAProcessList(); // Try to stop all GTA process id's @@ -395,6 +425,17 @@ bool IsOtherMTARunning() /////////////////////////////////////////////////////////////////////////// void TerminateOtherMTAIfRunning() { + if (IsSecondaryClient()) + return; + + // Don't terminate other MTA if CL2 is running + HANDLE hCL2Mutex = OpenMutexA(SYNCHRONIZE, FALSE, MTA_GUID_CL2); + if (hCL2Mutex) + { + CloseHandle(hCL2Mutex); + return; + } + std::vector processIdList = GetOtherMTAProcessList(); if (processIdList.size()) @@ -1193,12 +1234,16 @@ bool TerminateProcess(DWORD dwProcessID, uint uiExitCode) // // CreateSingleInstanceMutex // -// +// Create mutex to prevent multiple instances +// Secondary client (-cl2) uses a different GUID // /////////////////////////////////////////////////////////////////////////// bool CreateSingleInstanceMutex() { - HANDLE hMutex = CreateMutex(NULL, FALSE, TEXT(MTA_GUID)); + // Use different GUID for secondary client + const char* szGuid = IsSecondaryClient() ? MTA_GUID_CL2 : MTA_GUID; + + HANDLE hMutex = CreateMutex(NULL, FALSE, TEXT(szGuid)); if (GetLastError() == ERROR_ALREADY_EXISTS) { @@ -1220,6 +1265,9 @@ bool CreateSingleInstanceMutex() /////////////////////////////////////////////////////////////////////////// void ReleaseSingleInstanceMutex() { + if (IsSecondaryClient()) + return; + // assert(g_hMutex); CloseHandle(g_hMutex); g_hMutex = NULL; diff --git a/Client/loader/Utils.h b/Client/loader/Utils.h index da23c81e618..e87f3aa9d50 100644 --- a/Client/loader/Utils.h +++ b/Client/loader/Utils.h @@ -66,6 +66,7 @@ struct SPEFileOffsets void TerminateGTAIfRunning(); bool IsGTARunning(); +bool IsSecondaryClient(); void TerminateOtherMTAIfRunning(); bool IsOtherMTARunning(); diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 796c8876658..e6f3b1293f8 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -326,7 +326,12 @@ CClientGame::CClientGame(bool bLocalPlay) : m_ServerInfo(new CServerInfo()) m_pLuaManager = new CLuaManager(this); m_pScriptDebugging = new CScriptDebugging(m_pLuaManager); - m_pScriptDebugging->SetLogfile(CalcMTASAPath("mta\\logs\\clientscript.log"), 3); + SString strScriptLog = "mta\\logs\\clientscript.log"; + if (g_pCore->IsSecondaryClient()) + { + strScriptLog = "mta\\logs\\clientscript-cl2.log"; + } + m_pScriptDebugging->SetLogfile(CalcMTASAPath(strScriptLog), 3); CStaticFunctionDefinitions(m_pLuaManager, &m_Events, g_pCore, g_pGame, this, m_pManager); CLuaFunctionDefs::Initialize(m_pLuaManager, m_pScriptDebugging, this); @@ -6755,12 +6760,20 @@ void CClientGame::SetFileCacheRoot() // Check exists if (!strFileCachePath.empty() && DirectoryExists(strFileCachePath)) { - // Check writable - SString strTestFileName = PathJoin(strFileCachePath, "resources", "_test.tmp"); + // Check writable - use -cl2 suffix for secondary client folders + SString strResourcesDir = "resources"; + SString strPrivDir = "priv"; + if (g_pCore->IsSecondaryClient()) + { + strResourcesDir = "resources-cl2"; + strPrivDir = "priv-cl2"; + } + + SString strTestFileName = PathJoin(strFileCachePath, strResourcesDir, "_test.tmp"); if (FileSave(strTestFileName, "x")) { FileDelete(strTestFileName); - strTestFileName = PathJoin(strFileCachePath, "priv", "_test.tmp"); + strTestFileName = PathJoin(strFileCachePath, strPrivDir, "_test.tmp"); if (FileSave(strTestFileName, "x")) { FileDelete(strTestFileName); diff --git a/Client/mods/deathmatch/logic/CResource.cpp b/Client/mods/deathmatch/logic/CResource.cpp index d1d9be1f8ea..71bb8567037 100644 --- a/Client/mods/deathmatch/logic/CResource.cpp +++ b/Client/mods/deathmatch/logic/CResource.cpp @@ -73,7 +73,13 @@ CResource::CResource(unsigned short usNetID, const char* szResourceName, CClient m_pResourceIMGRoot = new CClientDummy(g_pClientGame->GetManager(), INVALID_ELEMENT_ID, "imgroot"); m_pResourceIMGRoot->MakeSystemEntity(); - m_strResourceDirectoryPath = SString("%s/resources/%s", g_pClientGame->GetFileCacheRoot(), *m_strResourceName); + // Use resources-cl2 for secondary client + SString strResourcesDir = "resources"; + if (g_pCore->IsSecondaryClient()) + { + strResourcesDir = "resources-cl2"; + } + m_strResourceDirectoryPath = SString("%s/%s/%s", g_pClientGame->GetFileCacheRoot(), *strResourcesDir, *m_strResourceName); m_strResourcePrivateDirectoryPath = PathJoin(CServerIdManager::GetSingleton()->GetConnectionPrivateDirectory(), m_strResourceName); m_strResourcePrivateDirectoryPathOld = CServerIdManager::GetSingleton()->GetConnectionPrivateDirectory(true); @@ -189,8 +195,13 @@ CResource::~CResource() CDownloadableResource* CResource::AddResourceFile(CDownloadableResource::eResourceType resourceType, const char* szFileName, uint uiDownloadSize, CChecksum serverChecksum, bool bAutoDownload) { - // Create the resource file and add it to the list - SString strBuffer("%s\\resources\\%s\\%s", g_pClientGame->GetFileCacheRoot(), *m_strResourceName, szFileName); + // Create the resource file and add it to the list - use resources-cl2 for secondary client + SString strResourcesDir = "resources"; + if (g_pCore->IsSecondaryClient()) + { + strResourcesDir = "resources-cl2"; + } + SString strBuffer("%s\\%s\\%s\\%s", g_pClientGame->GetFileCacheRoot(), *strResourcesDir, *m_strResourceName, szFileName); // Reject duplicates if (g_pClientGame->GetResourceManager()->IsResourceFile(strBuffer)) @@ -210,8 +221,13 @@ CDownloadableResource* CResource::AddResourceFile(CDownloadableResource::eResour CDownloadableResource* CResource::AddConfigFile(const char* szFileName, uint uiDownloadSize, CChecksum serverChecksum) { - // Create the config file and add it to the list - SString strBuffer("%s\\resources\\%s\\%s", g_pClientGame->GetFileCacheRoot(), *m_strResourceName, szFileName); + // Create the config file and add it to the list - use resources-cl2 for secondary client + SString strResourcesDir = "resources"; + if (g_pCore->IsSecondaryClient()) + { + strResourcesDir = "resources-cl2"; + } + SString strBuffer("%s\\%s\\%s\\%s", g_pClientGame->GetFileCacheRoot(), *strResourcesDir, *m_strResourceName, szFileName); // Reject duplicates if (g_pClientGame->GetResourceManager()->IsResourceFile(strBuffer)) diff --git a/Client/mods/deathmatch/logic/CServerIdManager.cpp b/Client/mods/deathmatch/logic/CServerIdManager.cpp index 983eaf8f151..2a35a785e2d 100644 --- a/Client/mods/deathmatch/logic/CServerIdManager.cpp +++ b/Client/mods/deathmatch/logic/CServerIdManager.cpp @@ -15,6 +15,8 @@ #define MTA_SERVERID_LOOKUP_DIR "priv" #define MTA_SERVERID_LOOKUP_XML "priv/server-ids.xml" +#define MTA_SERVERID_LOOKUP_DIR_CL2 "priv-cl2" +#define MTA_SERVERID_LOOKUP_XML_CL2 "priv-cl2/server-ids.xml" namespace { @@ -98,8 +100,13 @@ CServerIdManager* CServerIdManager::GetSingleton() /////////////////////////////////////////////////////////////// CServerIdManagerImpl::CServerIdManagerImpl() { - // Calc private dir root - m_strServerIdLookupBaseDir = PathJoin(g_pClientGame->GetFileCacheRoot(), MTA_SERVERID_LOOKUP_DIR); + // Calc private dir root - use priv-cl2 for secondary client + SString strPrivDir = MTA_SERVERID_LOOKUP_DIR; + if (g_pCore->IsSecondaryClient()) + { + strPrivDir = MTA_SERVERID_LOOKUP_DIR_CL2; + } + m_strServerIdLookupBaseDir = PathJoin(g_pClientGame->GetFileCacheRoot(), strPrivDir); MakeSureDirExists(PathJoin(m_strServerIdLookupBaseDir, "")); // Calc temp dir path incase of server id error @@ -132,8 +139,13 @@ CServerIdManagerImpl::~CServerIdManagerImpl() /////////////////////////////////////////////////////////////// bool CServerIdManagerImpl::LoadServerIdMap() { - // Load config XML file - CXMLFile* pConfigFile = g_pCore->GetXML()->CreateXML(PathJoin(g_pClientGame->GetFileCacheRoot(), MTA_SERVERID_LOOKUP_XML)); + // Load config XML file - use priv-cl2 for secondary client + SString strServerIdXml = MTA_SERVERID_LOOKUP_XML; + if (g_pCore->IsSecondaryClient()) + { + strServerIdXml = MTA_SERVERID_LOOKUP_XML_CL2; + } + CXMLFile* pConfigFile = g_pCore->GetXML()->CreateXML(PathJoin(g_pClientGame->GetFileCacheRoot(), strServerIdXml)); if (!pConfigFile) return false; pConfigFile->Parse(); @@ -235,7 +247,13 @@ DWORD WINAPI CServerIdManagerImpl::StaticThreadProc(LPVOID lpdwThreadParam) /////////////////////////////////////////////////////////////// void CServerIdManagerImpl::StaticSaveServerIdMap() { - CXMLFile* pConfigFile = g_pCore->GetXML()->CreateXML(PathJoin(g_pClientGame->GetFileCacheRoot(), MTA_SERVERID_LOOKUP_XML)); + // Use priv-cl2 for secondary client + SString strServerIdXml = MTA_SERVERID_LOOKUP_XML; + if (g_pCore->IsSecondaryClient()) + { + strServerIdXml = MTA_SERVERID_LOOKUP_XML_CL2; + } + CXMLFile* pConfigFile = g_pCore->GetXML()->CreateXML(PathJoin(g_pClientGame->GetFileCacheRoot(), strServerIdXml)); if (!pConfigFile) return; pConfigFile->Reset(); diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 6e91ea3b3a7..5aae7ae16b9 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -246,7 +246,14 @@ bool CStaticFunctionDefinitions::WasEventCancelled() bool CStaticFunctionDefinitions::DownloadFile(CResource* pResource, const char* szFile, CResource* pRequestResource, CChecksum checksum) { SString strHTTPDownloadURLFull("%s/%s/%s", g_pClientGame->GetHTTPURL().c_str(), pResource->GetName(), szFile); - SString strPath("%s\\resources\\%s\\%s", g_pClientGame->GetFileCacheRoot(), pResource->GetName(), szFile); + + // Use resources-cl2 for secondary client + SString strResourcesDir = "resources"; + if (g_pCore->IsSecondaryClient()) + { + strResourcesDir = "resources-cl2"; + } + SString strPath("%s\\%s\\%s\\%s", g_pClientGame->GetFileCacheRoot(), *strResourcesDir, pResource->GetName(), szFile); // Call SingularFileDownloadManager if (g_pClientGame->GetSingularFileDownloadManager()) diff --git a/Client/sdk/core/CCoreInterface.h b/Client/sdk/core/CCoreInterface.h index 42abefacf04..a2bb9b333de 100644 --- a/Client/sdk/core/CCoreInterface.h +++ b/Client/sdk/core/CCoreInterface.h @@ -131,6 +131,7 @@ class CCoreInterface virtual HWND GetHookedWindow() = 0; virtual bool IsFocused() = 0; virtual bool IsWindowMinimized() = 0; + virtual bool IsSecondaryClient() = 0; virtual void SaveConfig(bool bWaitUntilFinished = false) = 0; virtual void UpdateRecentlyPlayed() = 0;