From 371be5f12017cb9359e793427f786ff42f5be11d Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sun, 25 Jun 2023 14:00:28 +0200 Subject: [PATCH 1/8] Streaming memory changer functions --- Client/core/CCore.cpp | 24 +++++++++++++++++ Client/core/CCore.h | 13 +++++++-- Client/mods/deathmatch/logic/CClientGame.cpp | 27 ++++++++++--------- Client/mods/deathmatch/logic/CClientGame.h | 6 ++--- .../logic/luadefs/CLuaEngineDefs.cpp | 11 ++++++++ Client/sdk/core/CCoreInterface.h | 4 +++ 6 files changed, 68 insertions(+), 17 deletions(-) diff --git a/Client/core/CCore.cpp b/Client/core/CCore.cpp index dbd69730bca..6f6b7419c5b 100644 --- a/Client/core/CCore.cpp +++ b/Client/core/CCore.cpp @@ -2316,3 +2316,27 @@ SString CCore::GetBlueCopyrightString() SString strCopyright = BLUE_COPYRIGHT_STRING; return strCopyright.Replace("%BUILD_YEAR%", std::to_string(BUILD_YEAR).c_str()); } + +// Set streaming memory size override [See `engineStreamingSetMemorySize`] +void CCore::SetCustomStreamingMemory(size_t szMB) { + m_CustomStreamingMemoryLimitMB = szMB; +} + +bool CCore::IsUsingCustomStreamingMemorySize() +{ + return m_CustomStreamingMemoryLimitMB != 0; +} + +// Streaming memory size used [In MB] +size_t CCore::GetStreamingMemory() +{ + // If custom override is set, use that + if (IsUsingCustomStreamingMemorySize()) { + return m_CustomStreamingMemoryLimitMB; + } + + // Otherwise client CVar setting + size_t streamingMemSzCVar; + CVARS_GET_VALUE("streaming_memory", streamingMemSzCVar); + return streamingMemSzCVar; +} diff --git a/Client/core/CCore.h b/Client/core/CCore.h index ba4d69c66ed..61d064378f5 100644 --- a/Client/core/CCore.h +++ b/Client/core/CCore.h @@ -279,6 +279,9 @@ class CCore : public CCoreInterface, public CSingleton SString GetBlueCopyrightString(); bool IsFirstFrame() const noexcept { return m_bFirstFrame; } + void SetCustomStreamingMemory(size_t szMB); + bool IsUsingCustomStreamingMemorySize(); + size_t GetStreamingMemory(); private: void ApplyCoreInitSettings(); @@ -360,8 +363,14 @@ class CCore : public CCoreInterface, public CSingleton bool m_bWaitToSetNick; uint m_uiNewNickWaitFrames; EDiagnosticDebugType m_DiagnosticDebug; - float m_fMinStreamingMemory; - float m_fMaxStreamingMemory; + + // Below 2 are used for the UI only + float m_fMinStreamingMemory{}; + float m_fMaxStreamingMemory{}; + + // Custom streaming memory limit set by `engineStreamingSetMemorySize` - Reset on server connects (= set to 0), or by the scripter + size_t m_CustomStreamingMemoryLimitMB{}; + bool m_bGettingIdleCallsFromMultiplayer; bool m_bWindowsTimerEnabled; bool m_bModulesLoaded; diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index cee25e7987a..94de97b0610 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -880,18 +880,21 @@ void CClientGame::DoPulsePostFrame() DT_NOCLIP | DT_CENTER); } - // Adjust the streaming memory limit. - unsigned int uiStreamingMemoryPrev; - g_pCore->GetCVars()->Get("streaming_memory", uiStreamingMemoryPrev); - uint uiStreamingMemory = SharedUtil::Clamp(g_pCore->GetMinStreamingMemory(), uiStreamingMemoryPrev, g_pCore->GetMaxStreamingMemory()); - if (uiStreamingMemory != uiStreamingMemoryPrev) - g_pCore->GetCVars()->Set("streaming_memory", uiStreamingMemory); - - int iStreamingMemoryBytes = static_cast(uiStreamingMemory) * 1024 * 1024; - if (g_pMultiplayer->GetLimits()->GetStreamingMemory() != iStreamingMemoryBytes) - g_pMultiplayer->GetLimits()->SetStreamingMemory(iStreamingMemoryBytes); - - // If we're in debug mode and are supposed to show task data, do it + // Adjust the streaming memory size cvar [if needed] + if (!g_pCore->IsUsingCustomStreamingMemorySize()) { + unsigned int uiStreamingMemoryPrev; + g_pCore->GetCVars()->Get("streaming_memory", uiStreamingMemoryPrev); + uint uiStreamingMemory = SharedUtil::Clamp(g_pCore->GetMinStreamingMemory(), uiStreamingMemoryPrev, g_pCore->GetMaxStreamingMemory()); + if (uiStreamingMemory != uiStreamingMemoryPrev) + g_pCore->GetCVars()->Set("streaming_memory", uiStreamingMemory); + } + + const auto streamingMemorySizeBytes = static_cast(g_pCore->GetStreamingMemory()) * 1024 * 1024; // Convert to bytes + if (g_pMultiplayer->GetLimits()->GetStreamingMemory() != streamingMemorySizeBytes) { + g_pMultiplayer->GetLimits()->SetStreamingMemory(streamingMemorySizeBytes); + } + + // If we're in debug mode and are supposed to show task data, do it #ifdef MTA_DEBUG if (m_pShowPlayerTasks) { diff --git a/Client/mods/deathmatch/logic/CClientGame.h b/Client/mods/deathmatch/logic/CClientGame.h index d1e15339aea..7f06f6b3bb8 100644 --- a/Client/mods/deathmatch/logic/CClientGame.h +++ b/Client/mods/deathmatch/logic/CClientGame.h @@ -804,9 +804,9 @@ class CClientGame bool m_bDoPaintballs; bool m_bShowInterpolation; #endif - bool m_bDevelopmentMode; - bool m_bShowCollision; - bool m_bShowSound; + bool m_bDevelopmentMode; + bool m_bShowCollision; + bool m_bShowSound; // Debug class. Empty in release. public: diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp index bb4335176ff..8f06357e425 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp @@ -25,6 +25,15 @@ std::uint32_t EngineStreamingGetUsedMemory() return g_pGame->GetStreaming()->GetMemoryUsed(); } +bool EngineStreamingSetMemorySize(size_t sizeMB) { + g_pCore->SetCustomStreamingMemory(sizeMB); + return true; +} + +size_t EngineStreamingGetMemorySize() { + return g_pCore->GetStreamingMemory(); +} + void CLuaEngineDefs::LoadFunctions() { constexpr static const std::pair functions[]{ @@ -82,6 +91,8 @@ void CLuaEngineDefs::LoadFunctions() {"engineGetModelTXDID", ArgumentParser}, {"engineStreamingFreeUpMemory", ArgumentParser}, {"engineStreamingGetUsedMemory", ArgumentParser}, + {"engineStreamingSetMemorySize", ArgumentParser}, + {"engineStreamingGetMemorySize", ArgumentParser}, // CLuaCFunctions::AddFunction ( "engineReplaceMatchingAtomics", EngineReplaceMatchingAtomics ); // CLuaCFunctions::AddFunction ( "engineReplaceWheelAtomics", EngineReplaceWheelAtomics ); diff --git a/Client/sdk/core/CCoreInterface.h b/Client/sdk/core/CCoreInterface.h index 2f55c202202..ba231414e1f 100644 --- a/Client/sdk/core/CCoreInterface.h +++ b/Client/sdk/core/CCoreInterface.h @@ -179,6 +179,10 @@ class CCoreInterface virtual void ResetChatboxCharacterLimit() = 0; virtual int GetChatboxCharacterLimit() = 0; virtual int GetChatboxMaxCharacterLimit() = 0; + + virtual void SetCustomStreamingMemory(size_t szMB) = 0; + virtual bool IsUsingCustomStreamingMemorySize() = 0; + virtual size_t GetStreamingMemory() = 0; }; class CClientTime From 7ff4f48cbd2ea48daa730d008f766398f4ee71df Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sun, 25 Jun 2023 15:42:15 +0200 Subject: [PATCH 2/8] Fix code --- Client/core/CCore.cpp | 12 +++--------- Shared/sdk/version.h | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Client/core/CCore.cpp b/Client/core/CCore.cpp index 6f6b7419c5b..b5c163364b6 100644 --- a/Client/core/CCore.cpp +++ b/Client/core/CCore.cpp @@ -2330,13 +2330,7 @@ bool CCore::IsUsingCustomStreamingMemorySize() // Streaming memory size used [In MB] size_t CCore::GetStreamingMemory() { - // If custom override is set, use that - if (IsUsingCustomStreamingMemorySize()) { - return m_CustomStreamingMemoryLimitMB; - } - - // Otherwise client CVar setting - size_t streamingMemSzCVar; - CVARS_GET_VALUE("streaming_memory", streamingMemSzCVar); - return streamingMemSzCVar; + return IsUsingCustomStreamingMemorySize() + ? m_CustomStreamingMemoryLimitMB + : CVARS_GET_VALUE("streaming_memory", 0); } diff --git a/Shared/sdk/version.h b/Shared/sdk/version.h index b6697e65471..7a8ec4f1d86 100644 --- a/Shared/sdk/version.h +++ b/Shared/sdk/version.h @@ -28,7 +28,7 @@ #define MTASA_VERSION_MAJOR 1 #define MTASA_VERSION_MINOR 6 #define MTASA_VERSION_MAINTENANCE 0 -#define MTASA_VERSION_TYPE VERSION_TYPE_UNSTABLE +#define MTASA_VERSION_TYPE VERSION_TYPE_CUSTOM #define MTASA_VERSION_BUILD 0 #include "../build_overrides.h" From 2cd935e16fe1a58416fa50ae647b5bedc2a5f001 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sun, 25 Jun 2023 16:00:30 +0200 Subject: [PATCH 3/8] Fix streaming memory values displayed incorrectly when above signed int limit --- Client/core/CMemStats.cpp | 4 ++-- Client/core/CMemStats.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Client/core/CMemStats.cpp b/Client/core/CMemStats.cpp index 9c5b12b8e48..7253b8a1cd1 100644 --- a/Client/core/CMemStats.cpp +++ b/Client/core/CMemStats.cpp @@ -472,8 +472,8 @@ void CMemStats::SampleState(SMemStatsInfo& memStatsInfo) memStatsInfo.iProcessTotalVirtualKB = status.ullTotalVirtual / 1024LL; } - memStatsInfo.iStreamingMemoryUsed = *(int*)0x08E4CB4; - memStatsInfo.iStreamingMemoryAvailable = *(int*)0x08A5A80; + memStatsInfo.iStreamingMemoryUsed = *(size_t*)0x08E4CB4; + memStatsInfo.iStreamingMemoryAvailable = *(size_t*)0x08A5A80; char* pFileInfoArray = *(char**)(0x5B8B08 + 6); CGame* pGame = g_pCore->GetGame(); diff --git a/Client/core/CMemStats.h b/Client/core/CMemStats.h index 1fcf5a64d4a..a239198bd67 100644 --- a/Client/core/CMemStats.h +++ b/Client/core/CMemStats.h @@ -26,10 +26,10 @@ struct SMemStatsInfo CProxyDirect3DDevice9::SMemoryState d3dMemory; CProxyDirect3DDevice9::SFrameStats frameStats; SDxStatus dxStatus; - int iProcessMemSizeKB; - int iProcessTotalVirtualKB; - int iStreamingMemoryUsed; - int iStreamingMemoryAvailable; + size_t iProcessMemSizeKB; + size_t iProcessTotalVirtualKB; + size_t iStreamingMemoryUsed; + size_t iStreamingMemoryAvailable; SRwResourceStats rwResourceStats; SClothesCacheStats clothesCacheStats; SShaderReplacementStats shaderReplacementStats; From 39d04a8c29bfbfadc6e0a1368e95c738bd33aab2 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sun, 25 Jun 2023 16:00:41 +0200 Subject: [PATCH 4/8] Reset custom streaming memory size on disconnect --- Client/mods/deathmatch/logic/CClientGame.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 94de97b0610..a87e4431919 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -529,6 +529,9 @@ CClientGame::~CClientGame() m_bBeingDeleted = false; CStaticFunctionDefinitions::ResetAllSurfaceInfo(); + + // Reset custom streaming memory size [possibly] set by the server + g_pCore->SetCustomStreamingMemory(0); } /* From 799ab532fae3abbbf29a7ca4f63f19d381d9c903 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sun, 25 Jun 2023 16:52:26 +0200 Subject: [PATCH 5/8] Refactor --- Client/core/CCore.cpp | 15 +++++---- Client/core/CCore.h | 3 +- Client/mods/deathmatch/logic/CClientGame.cpp | 2 +- .../logic/luadefs/CLuaEngineDefs.cpp | 31 +++++++++++++++++-- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/Client/core/CCore.cpp b/Client/core/CCore.cpp index b5c163364b6..18968d2bc17 100644 --- a/Client/core/CCore.cpp +++ b/Client/core/CCore.cpp @@ -2318,19 +2318,22 @@ SString CCore::GetBlueCopyrightString() } // Set streaming memory size override [See `engineStreamingSetMemorySize`] -void CCore::SetCustomStreamingMemory(size_t szMB) { - m_CustomStreamingMemoryLimitMB = szMB; +// Use `0` to turn it off, and thus restore the value to the `cvar` setting +void CCore::SetCustomStreamingMemory(size_t sizeBytes) { + // NOTE: The override is applied to the game in `CClientGame::DoPulsePostFrame` + // There's no specific reason we couldn't do it here, but we wont + m_CustomStreamingMemoryLimitBytes = sizeBytes; } bool CCore::IsUsingCustomStreamingMemorySize() { - return m_CustomStreamingMemoryLimitMB != 0; + return m_CustomStreamingMemoryLimitBytes != 0; } -// Streaming memory size used [In MB] +// Streaming memory size used [In Bytes] size_t CCore::GetStreamingMemory() { return IsUsingCustomStreamingMemorySize() - ? m_CustomStreamingMemoryLimitMB - : CVARS_GET_VALUE("streaming_memory", 0); + ? m_CustomStreamingMemoryLimitBytes + : CVARS_GET_VALUE("streaming_memory") * 1024 * 1024; // MB to B conversion } diff --git a/Client/core/CCore.h b/Client/core/CCore.h index 61d064378f5..698af7e1723 100644 --- a/Client/core/CCore.h +++ b/Client/core/CCore.h @@ -369,7 +369,8 @@ class CCore : public CCoreInterface, public CSingleton float m_fMaxStreamingMemory{}; // Custom streaming memory limit set by `engineStreamingSetMemorySize` - Reset on server connects (= set to 0), or by the scripter - size_t m_CustomStreamingMemoryLimitMB{}; + // `0` means "not set" [so the value should be ignored] + size_t m_CustomStreamingMemoryLimitBytes{}; bool m_bGettingIdleCallsFromMultiplayer; bool m_bWindowsTimerEnabled; diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index a87e4431919..29655566f73 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -892,7 +892,7 @@ void CClientGame::DoPulsePostFrame() g_pCore->GetCVars()->Set("streaming_memory", uiStreamingMemory); } - const auto streamingMemorySizeBytes = static_cast(g_pCore->GetStreamingMemory()) * 1024 * 1024; // Convert to bytes + const auto streamingMemorySizeBytes = g_pCore->GetStreamingMemory(); if (g_pMultiplayer->GetLimits()->GetStreamingMemory() != streamingMemorySizeBytes) { g_pMultiplayer->GetLimits()->SetStreamingMemory(streamingMemorySizeBytes); } diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp index 8f06357e425..1e641d10dd3 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp @@ -20,16 +20,26 @@ void EngineStreamingFreeUpMemory(std::uint32_t bytes) g_pGame->GetStreaming()->MakeSpaceFor(bytes); } +// Get currenlty used memory for stremaing [In bytes] std::uint32_t EngineStreamingGetUsedMemory() { return g_pGame->GetStreaming()->GetMemoryUsed(); } -bool EngineStreamingSetMemorySize(size_t sizeMB) { - g_pCore->SetCustomStreamingMemory(sizeMB); - return true; +// Set the streaming memory size to a custom value +void EngineStreamingSetMemorySize(size_t sizeBytes) { + if (sizeBytes == 0) { + throw std::invalid_argument{"Memory size must be > 0"}; + } + g_pCore->SetCustomStreamingMemory(sizeBytes); +} + +// Restore memory size to cvar +void EngineStreamingRestoreMemorySize() { + g_pCore->SetCustomStreamingMemory(0); } +// Get the streaming memory size [In bytes] - This is the limit, not the amount currently used! [See `EngineStreamingGetUsedMemory`] size_t EngineStreamingGetMemorySize() { return g_pCore->GetStreamingMemory(); } @@ -93,6 +103,7 @@ void CLuaEngineDefs::LoadFunctions() {"engineStreamingGetUsedMemory", ArgumentParser}, {"engineStreamingSetMemorySize", ArgumentParser}, {"engineStreamingGetMemorySize", ArgumentParser}, + {"engineStreamingRestoreMemorySize", ArgumentParser}, // CLuaCFunctions::AddFunction ( "engineReplaceMatchingAtomics", EngineReplaceMatchingAtomics ); // CLuaCFunctions::AddFunction ( "engineReplaceWheelAtomics", EngineReplaceWheelAtomics ); @@ -140,6 +151,20 @@ void CLuaEngineDefs::AddClass(lua_State* luaVM) lua_registerstaticclass(luaVM, "Engine"); + // `EngineStreaming` class + lua_newclass(luaVM); + { + lua_classfunction(luaVM, "freeUpMemory", "engineStreamingFreeUpMemory"); + lua_classfunction(luaVM, "getUsedMemory", "engineStreamingGetUsedMemory"); + lua_classfunction(luaVM, "setMemorySize", "engineStreamingSetMemorySize"); + lua_classfunction(luaVM, "getMemorySize", "engineStreamingGetMemorySize"); + lua_classfunction(luaVM, "restoreMemorySize", "engineStreamingRestoreMemorySize"); + + lua_classvariable(luaVM, "memorySize", "engineStreamingSetMemorySize", "engineStreamingGetMemorySize"); + lua_classvariable(luaVM, "usedMemory", NULL, "engineStreamingGetUsedMemory"); + } + lua_registerstaticclass(luaVM, "EngineStreaming"); + AddEngineColClass(luaVM); AddEngineTxdClass(luaVM); AddEngineDffClass(luaVM); From d7eac8f27048c06dc1d200e081854fd2ab0b7f1d Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sun, 25 Jun 2023 16:56:10 +0200 Subject: [PATCH 6/8] Fix arg name --- Client/sdk/core/CCoreInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/sdk/core/CCoreInterface.h b/Client/sdk/core/CCoreInterface.h index ba231414e1f..cf90751f7f6 100644 --- a/Client/sdk/core/CCoreInterface.h +++ b/Client/sdk/core/CCoreInterface.h @@ -180,7 +180,7 @@ class CCoreInterface virtual int GetChatboxCharacterLimit() = 0; virtual int GetChatboxMaxCharacterLimit() = 0; - virtual void SetCustomStreamingMemory(size_t szMB) = 0; + virtual void SetCustomStreamingMemory(size_t sizeBytes) = 0; virtual bool IsUsingCustomStreamingMemorySize() = 0; virtual size_t GetStreamingMemory() = 0; }; From ccfcef2ac55bc31d67ccfbcd24d555d2bf2b7a83 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sun, 25 Jun 2023 16:57:46 +0200 Subject: [PATCH 7/8] Restore version.h --- Shared/sdk/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shared/sdk/version.h b/Shared/sdk/version.h index 7a8ec4f1d86..b6697e65471 100644 --- a/Shared/sdk/version.h +++ b/Shared/sdk/version.h @@ -28,7 +28,7 @@ #define MTASA_VERSION_MAJOR 1 #define MTASA_VERSION_MINOR 6 #define MTASA_VERSION_MAINTENANCE 0 -#define MTASA_VERSION_TYPE VERSION_TYPE_CUSTOM +#define MTASA_VERSION_TYPE VERSION_TYPE_UNSTABLE #define MTASA_VERSION_BUILD 0 #include "../build_overrides.h" From ed8f0d6009a251c42fe2bacae0bf3123b83e0d92 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Tue, 27 Jun 2023 21:00:55 +0200 Subject: [PATCH 8/8] get/setBufferSize --- Client/game_sa/CStreamingSA.cpp | 26 ++++++------- Client/game_sa/CStreamingSA.h | 2 +- Client/mods/deathmatch/logic/CClientIMG.cpp | 12 +++--- Client/mods/deathmatch/logic/CClientIMG.h | 8 ++-- .../deathmatch/logic/CClientIMGManager.cpp | 37 ++++++++++++++----- .../mods/deathmatch/logic/CClientIMGManager.h | 5 ++- .../logic/luadefs/CLuaEngineDefs.cpp | 21 +++++++++++ 7 files changed, 76 insertions(+), 35 deletions(-) diff --git a/Client/game_sa/CStreamingSA.cpp b/Client/game_sa/CStreamingSA.cpp index 7430e3576af..0427043ee7a 100644 --- a/Client/game_sa/CStreamingSA.cpp +++ b/Client/game_sa/CStreamingSA.cpp @@ -256,39 +256,39 @@ void CStreamingSA::RemoveArchive(unsigned char ucArhiveID) m_aStreamingHandlers[uiStreamHandlerID] = NULL; } -void CStreamingSA::SetStreamingBufferSize(uint32 uiBlockSize) +void CStreamingSA::SetStreamingBufferSize(uint32 numBlocks) { - if (uiBlockSize == ms_streamingHalfOfBufferSize * 2) + if (numBlocks == ms_streamingHalfOfBufferSize * 2) return; int pointer = *(int*)0x8E3FFC; SGtaStream(&streaming)[5] = *(SGtaStream(*)[5])(pointer); // Wait while streaming threads ends tasks - while (streaming[0].bInUse && streaming[1].bInUse) - - // Suspend streaming handle - SuspendThread(*phStreamingThread); + while (streaming[0].bInUse && streaming[1].bInUse); + // Suspend streaming handle + SuspendThread(*phStreamingThread); + // Create new buffer - if (uiBlockSize & 1) - uiBlockSize++; + if (numBlocks & 1) // Make it be even + numBlocks++; typedef void*(__cdecl * Function_CMemoryMgr_MallocAlign)(uint32 uiCount, uint32 uiAlign); - void* pNewBuffer = ((Function_CMemoryMgr_MallocAlign)(0x72F4C0))(uiBlockSize << 11, 2048); + void* pNewBuffer = ((Function_CMemoryMgr_MallocAlign)(0x72F4C0))(numBlocks * 2048, 2048); // Copy data from old buffer to new buffer - uint uiCopySize = std::min(ms_streamingHalfOfBufferSize, uiBlockSize / 2); + uint uiCopySize = std::min(ms_streamingHalfOfBufferSize, numBlocks / 2); // TODO: This probably won't work as expected MemCpyFast(pNewBuffer, (void*)ms_pStreamingBuffer[0], uiCopySize); - MemCpyFast((void*)(reinterpret_cast(pNewBuffer) + 1024 * uiBlockSize), (void*)ms_pStreamingBuffer[1], uiCopySize); + MemCpyFast((void*)(reinterpret_cast(pNewBuffer) + 1024 * numBlocks), (void*)ms_pStreamingBuffer[1], uiCopySize); typedef void(__cdecl * Function_CMemoryMgr_FreeAlign)(void* pos); ((Function_CMemoryMgr_FreeAlign)(0x72F4F0))(ms_pStreamingBuffer[0]); - ms_streamingHalfOfBufferSize = uiBlockSize / 2; + ms_streamingHalfOfBufferSize = numBlocks / 2; ms_pStreamingBuffer[0] = pNewBuffer; - ms_pStreamingBuffer[1] = (void*)(reinterpret_cast(pNewBuffer) + 1024 * uiBlockSize); + ms_pStreamingBuffer[1] = (void*)(reinterpret_cast(pNewBuffer) + 1024 * numBlocks); streaming[0].pBuffer = ms_pStreamingBuffer[0]; streaming[1].pBuffer = ms_pStreamingBuffer[1]; diff --git a/Client/game_sa/CStreamingSA.h b/Client/game_sa/CStreamingSA.h index 0338c24ace9..d5c7294c20b 100644 --- a/Client/game_sa/CStreamingSA.h +++ b/Client/game_sa/CStreamingSA.h @@ -66,7 +66,7 @@ class CStreamingSA final : public CStreaming unsigned char AddArchive(const char* szFilePath); void RemoveArchive(unsigned char ucStreamHandler); void SetStreamingBufferSize(uint32 uiSize); - uint32 GetStreamingBufferSize() { return ms_streamingHalfOfBufferSize * 2; }; + uint32 GetStreamingBufferSize() { return ms_streamingHalfOfBufferSize * 2; }; // In bytes void MakeSpaceFor(std::uint32_t memoryToCleanInBytes) override; std::uint32_t GetMemoryUsed() const override; diff --git a/Client/mods/deathmatch/logic/CClientIMG.cpp b/Client/mods/deathmatch/logic/CClientIMG.cpp index 5d553bbfd67..9ca421dac6f 100644 --- a/Client/mods/deathmatch/logic/CClientIMG.cpp +++ b/Client/mods/deathmatch/logic/CClientIMG.cpp @@ -20,7 +20,7 @@ struct tImgHeader }; CClientIMG::CClientIMG(class CClientManager* pManager, ElementID ID) - : ClassInit(this), CClientEntity(ID), m_pImgManager(pManager->GetIMGManager()), m_ucArchiveID(INVALID_ARCHIVE_ID), m_usRequiredBufferSize(0) + : ClassInit(this), CClientEntity(ID), m_pImgManager(pManager->GetIMGManager()), m_ucArchiveID(INVALID_ARCHIVE_ID), m_LargestFileSizeBlocks(0) { m_pManager = pManager; SetTypeName("img"); @@ -106,11 +106,11 @@ bool CClientIMG::GetFile(size_t fileID, std::string& buffer) if (!pFileInfo) throw std::invalid_argument("Invalid file id"); - const auto ulToReadSize = pFileInfo->usSize * 2048; + const auto toReadBytes = (size_t)pFileInfo->usSize * 2048u; try { - buffer.resize(ulToReadSize); + buffer.resize(toReadBytes); } catch (const std::bad_alloc&) { @@ -118,7 +118,7 @@ bool CClientIMG::GetFile(size_t fileID, std::string& buffer) } m_ifs.seekg((std::streampos)pFileInfo->uiOffset * 2048); - m_ifs.read(buffer.data(), ulToReadSize); + m_ifs.read(buffer.data(), toReadBytes); return !m_ifs.fail() && !m_ifs.eof(); } @@ -153,10 +153,10 @@ bool CClientIMG::StreamEnable() if (IsStreamed()) return false; - if (m_usRequiredBufferSize == 0) + if (m_LargestFileSizeBlocks == 0) { for (const auto& fileInfo : m_fileInfos) - m_usRequiredBufferSize = Max(m_usRequiredBufferSize, fileInfo.usSize); + m_LargestFileSizeBlocks = std::max(m_LargestFileSizeBlocks, (size_t)fileInfo.usSize); } m_ucArchiveID = g_pGame->GetStreaming()->AddArchive(m_filePath.c_str()); diff --git a/Client/mods/deathmatch/logic/CClientIMG.h b/Client/mods/deathmatch/logic/CClientIMG.h index 0c21959eae9..0aa51d178d0 100644 --- a/Client/mods/deathmatch/logic/CClientIMG.h +++ b/Client/mods/deathmatch/logic/CClientIMG.h @@ -55,10 +55,10 @@ class CClientIMG : public CClientEntity void SetPosition(const CVector& vecPosition){}; eClientEntityType GetType() const { return CCLIENTIMG; } - unsigned char GetArchiveID() { return m_ucArchiveID; } - unsigned int GetFilesCount() { return m_fileInfos.size(); } + unsigned char GetArchiveID() const { return m_ucArchiveID; } + unsigned int GetFilesCount() const { return m_fileInfos.size(); } const auto& GetFileInfos() const noexcept { return m_fileInfos; } - unsigned short GetRequiredBufferSize() { return m_usRequiredBufferSize; } + auto GetLargestFileSizeBlocks() const { return m_LargestFileSizeBlocks; } bool Load(fs::path filePath); void Unload(); @@ -81,7 +81,7 @@ class CClientIMG : public CClientEntity std::string m_filePath; unsigned char m_ucArchiveID; std::vector m_fileInfos; - unsigned short m_usRequiredBufferSize; + size_t m_LargestFileSizeBlocks; // The size of the largest file [in streaming blocks/sectors] std::vector m_restoreInfo; }; diff --git a/Client/mods/deathmatch/logic/CClientIMGManager.cpp b/Client/mods/deathmatch/logic/CClientIMGManager.cpp index 1c1d2161a4b..ea85f045d55 100644 --- a/Client/mods/deathmatch/logic/CClientIMGManager.cpp +++ b/Client/mods/deathmatch/logic/CClientIMGManager.cpp @@ -15,6 +15,14 @@ CClientIMGManager::CClientIMGManager(CClientManager* pManager) { // Init m_bRemoveFromList = true; + + // Buffer size as calculated by GTA - This is also the size of the largest file in all of the loaded IMGs + + // g_pGame->GetStreaming()->GetStreamingBufferSize() / 2048; + // TODO: In the default gta3.img the biggest file is 1260 sectors, so to be fail safe, we double it + // ideally, we'd just take this value from the game, but there's no clean/easy way to do that [without loading the img archives] + // so, for now, this is good enough + m_LargestFileSizeBlocks = m_GTALargestFileSizeBlocks = 1260 * 2; } CClientIMGManager::~CClientIMGManager() @@ -25,7 +33,6 @@ CClientIMGManager::~CClientIMGManager() void CClientIMGManager::InitDefaultBufferSize() { - m_uiDefaultStreamerBufferSize = g_pGame->GetStreaming()->GetStreamingBufferSize(); } CClientIMG* CClientIMGManager::GetElementFromArchiveID(unsigned char ucArchiveID) @@ -93,6 +100,21 @@ bool CClientIMGManager::RestoreModel(unsigned int uiModel) return false; } +size_t CClientIMGManager::CalculateLargestFile() const +{ + auto largest = m_GTALargestFileSizeBlocks; + + for (const auto img : m_List) + { + if (!img->IsStreamed()) + continue; + + largest = std::max(img->GetLargestFileSizeBlocks(), largest); + } + + return largest; +} + void CClientIMGManager::RemoveFromList(CClientIMG* pIMG) { // Can we remove anything from the list? @@ -104,15 +126,10 @@ void CClientIMGManager::RemoveFromList(CClientIMG* pIMG) void CClientIMGManager::UpdateStreamerBufferSize() { - ushort usRequestStreamSize = m_uiDefaultStreamerBufferSize; + m_LargestFileSizeBlocks = CalculateLargestFile(); - for (CClientIMG* pImg : m_List) - { - if (!pImg->IsStreamed()) - continue; - ushort usStreamSize = pImg->GetRequiredBufferSize(); - if (usStreamSize > usRequestStreamSize) - usRequestStreamSize = usStreamSize; + // Only update if necessary, otherwise leave it be [User might've set it manually - we don't want to touch that] + if (const auto s = g_pGame->GetStreaming(); m_LargestFileSizeBlocks > s->GetStreamingBufferSize()) { + s->SetStreamingBufferSize(m_LargestFileSizeBlocks); } - g_pGame->GetStreaming()->SetStreamingBufferSize(usRequestStreamSize); } diff --git a/Client/mods/deathmatch/logic/CClientIMGManager.h b/Client/mods/deathmatch/logic/CClientIMGManager.h index 706b8476a21..a16239e88b1 100644 --- a/Client/mods/deathmatch/logic/CClientIMGManager.h +++ b/Client/mods/deathmatch/logic/CClientIMGManager.h @@ -33,12 +33,15 @@ class CClientIMGManager bool RestoreModel(unsigned int uiModel); static bool IsLinkableModel(unsigned int uiModel); void UpdateStreamerBufferSize(); + auto GetLargestFileSizeBlocks() const { return m_LargestFileSizeBlocks; } private: + size_t CalculateLargestFile() const; void AddToList(CClientIMG* pIMG) { m_List.push_back(pIMG); } void RemoveFromList(CClientIMG* pIMG); std::list m_List; bool m_bRemoveFromList; - uint32 m_uiDefaultStreamerBufferSize; + uint32 m_GTALargestFileSizeBlocks; + uint32 m_LargestFileSizeBlocks; // Size of the largest file [in streaming blocks/sectors] in any of the loaded imgs }; diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp index 1e641d10dd3..4389a147ee5 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp @@ -44,6 +44,22 @@ size_t EngineStreamingGetMemorySize() { return g_pCore->GetStreamingMemory(); } +// Set streaming buffer size +bool EngineStreamingSetBufferSize(size_t sizeBytes) { + const auto sizeBlocks = sizeBytes / 2048; + if (sizeBlocks > g_pClientGame->GetManager()->GetIMGManager()->GetLargestFileSizeBlocks()) { // Can't allow it to be less than the largest file + g_pGame->GetStreaming()->SetStreamingBufferSize(sizeBlocks); + return true; + } else { + return false; + } +} + +// Get current streaming buffer size +size_t EngineStreamingGetBufferSize() { + return g_pGame->GetStreaming()->GetStreamingBufferSize(); +} + void CLuaEngineDefs::LoadFunctions() { constexpr static const std::pair functions[]{ @@ -104,6 +120,8 @@ void CLuaEngineDefs::LoadFunctions() {"engineStreamingSetMemorySize", ArgumentParser}, {"engineStreamingGetMemorySize", ArgumentParser}, {"engineStreamingRestoreMemorySize", ArgumentParser}, + {"engineStreamingSetBufferSize", ArgumentParser}, + {"engineStreamingGetBufferSize", ArgumentParser}, // CLuaCFunctions::AddFunction ( "engineReplaceMatchingAtomics", EngineReplaceMatchingAtomics ); // CLuaCFunctions::AddFunction ( "engineReplaceWheelAtomics", EngineReplaceWheelAtomics ); @@ -159,8 +177,11 @@ void CLuaEngineDefs::AddClass(lua_State* luaVM) lua_classfunction(luaVM, "setMemorySize", "engineStreamingSetMemorySize"); lua_classfunction(luaVM, "getMemorySize", "engineStreamingGetMemorySize"); lua_classfunction(luaVM, "restoreMemorySize", "engineStreamingRestoreMemorySize"); + lua_classfunction(luaVM, "getBufferSize", "engineStreamingGetBufferSize"); + lua_classfunction(luaVM, "setBufferSize", "engineStreamingSetBufferSize"); lua_classvariable(luaVM, "memorySize", "engineStreamingSetMemorySize", "engineStreamingGetMemorySize"); + lua_classvariable(luaVM, "bufferSize", "engineStreamingSetBufferSize", "engineStreamingGetMemorySize"); lua_classvariable(luaVM, "usedMemory", NULL, "engineStreamingGetUsedMemory"); } lua_registerstaticclass(luaVM, "EngineStreaming");