Skip to content

Commit

Permalink
Streaming buffer restore + and fixes to EngineStreaming.bufferSize
Browse files Browse the repository at this point in the history
…(PR #3163)
  • Loading branch information
Pirulax committed Sep 8, 2023
1 parent 938b306 commit 6c86ebb
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 34 deletions.
51 changes: 31 additions & 20 deletions Client/game_sa/CStreamingSA.cpp
Expand Up @@ -21,7 +21,7 @@ extern CCoreInterface* g_pCore;
// count: 26316 in unmodified game
CStreamingInfo (&CStreamingSA::ms_aInfoForModel)[26316] = *(CStreamingInfo(*)[26316])0x8E4CC0;
HANDLE* phStreamingThread = (HANDLE*)0x8E4008;
uint32(&CStreamingSA::ms_streamingHalfOfBufferSize) = *(uint32*)0x8E4CA8;
uint32(&CStreamingSA::ms_streamingHalfOfBufferSizeBlocks) = *(uint32*)0x8E4CA8;
void* (&CStreamingSA::ms_pStreamingBuffer)[2] = *(void* (*)[2])0x8E4CAC;

namespace
Expand Down Expand Up @@ -429,45 +429,56 @@ void CStreamingSA::RemoveArchive(unsigned char ucArchiveID)
m_StreamHandles[uiStreamHandlerID] = NULL;
}

void CStreamingSA::SetStreamingBufferSize(uint32 numBlocks)
bool CStreamingSA::SetStreamingBufferSize(uint32 numBlocks)
{
if (numBlocks == ms_streamingHalfOfBufferSize * 2)
return;
// Check if the size is the same already
if (numBlocks == ms_streamingHalfOfBufferSizeBlocks * 2)
return true;

// First of all, allocate the new buffer
// NOTE: Due to a bug in the `MallocAlign` code the function will just *crash* instead of returning nullptr on alloc. failure :D
typedef void*(__cdecl * Function_CMemoryMgr_MallocAlign)(uint32 uiCount, uint32 uiAlign);
void* pNewBuffer = ((Function_CMemoryMgr_MallocAlign)(0x72F4C0))(numBlocks * 2048, 2048);
if (!pNewBuffer) // ...so this code is useless for now
return false;

int pointer = *(int*)0x8E3FFC;
SGtaStream(&streaming)[5] = *(SGtaStream(*)[5])(pointer);

// Wait while streaming threads ends tasks
while (streaming[0].bInUse && streaming[1].bInUse);
// Wait while streaming thread ends tasks
while (streaming[0].bInUse || streaming[1].bInUse);

// Suspend streaming handle
// Suspend streaming thread [otherwise data might become corrupted]
SuspendThread(*phStreamingThread);

// Create new buffer
if (numBlocks & 1) // Make it be even
if (numBlocks & 1) // Make it be even [Otherwise it can't be split in half properly]
numBlocks++;

typedef void*(__cdecl * Function_CMemoryMgr_MallocAlign)(uint32 uiCount, uint32 uiAlign);
void* pNewBuffer = ((Function_CMemoryMgr_MallocAlign)(0x72F4C0))(numBlocks * 2048, 2048);
// Calculate new buffer pointers
void* const pNewBuff0 = pNewBuffer;
void* const pNewBuff1 = (void*)(reinterpret_cast<uintptr_t>(pNewBuffer) + 2048u * (numBlocks / 2));

// Copy data from old buffer to new buffer
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<int>(pNewBuffer) + 1024 * numBlocks), (void*)ms_pStreamingBuffer[1], uiCopySize);
const auto copySizeBytes = std::min(ms_streamingHalfOfBufferSizeBlocks, numBlocks / 2) * 2048;
MemCpyFast(pNewBuff0, ms_pStreamingBuffer[0], copySizeBytes);
MemCpyFast(pNewBuff1, ms_pStreamingBuffer[1], copySizeBytes);

// Now, we can deallocate the old buffer safely
typedef void(__cdecl * Function_CMemoryMgr_FreeAlign)(void* pos);
((Function_CMemoryMgr_FreeAlign)(0x72F4F0))(ms_pStreamingBuffer[0]);

ms_streamingHalfOfBufferSize = numBlocks / 2;
// Update the buffer size now
ms_streamingHalfOfBufferSizeBlocks = numBlocks / 2;

ms_pStreamingBuffer[0] = pNewBuffer;
ms_pStreamingBuffer[1] = (void*)(reinterpret_cast<int>(pNewBuffer) + 1024 * numBlocks);
// Update internal pointers too
streaming[0].pBuffer = ms_pStreamingBuffer[0] = pNewBuff0;
streaming[1].pBuffer = ms_pStreamingBuffer[1] = pNewBuff1;

streaming[0].pBuffer = ms_pStreamingBuffer[0];
streaming[1].pBuffer = ms_pStreamingBuffer[1];

// Well done
// Now we can resume streaming
ResumeThread(*phStreamingThread);

return true;
}

void CStreamingSA::MakeSpaceFor(std::uint32_t memoryToCleanInBytes)
Expand Down
8 changes: 4 additions & 4 deletions Client/game_sa/CStreamingSA.h
Expand Up @@ -70,9 +70,9 @@ class CStreamingSA final : public CStreaming
unsigned char GetUnusedArchive();
unsigned char GetUnusedStreamHandle();
unsigned char AddArchive(const char* szFilePath);
void RemoveArchive(unsigned char ucArchiveID);
void SetStreamingBufferSize(uint32 uiSize);
uint32 GetStreamingBufferSize() { return ms_streamingHalfOfBufferSize * 2; }; // In bytes
void RemoveArchive(unsigned char ucStreamHandler);
bool SetStreamingBufferSize(uint32 uiSize);
uint32 GetStreamingBufferSize() { return ms_streamingHalfOfBufferSizeBlocks * 2048 * 2; }; // In bytes

void MakeSpaceFor(std::uint32_t memoryToCleanInBytes) override;
std::uint32_t GetMemoryUsed() const override;
Expand All @@ -85,6 +85,6 @@ class CStreamingSA final : public CStreaming
std::vector<SStreamName> m_StreamNames;

static void* (&ms_pStreamingBuffer)[2];
static uint32(&ms_streamingHalfOfBufferSize);
static uint32(&ms_streamingHalfOfBufferSizeBlocks);
static CStreamingInfo (&ms_aInfoForModel)[26316]; // count: 26316 in unmodified game
};
11 changes: 7 additions & 4 deletions Client/mods/deathmatch/logic/CClientGame.cpp
Expand Up @@ -370,10 +370,16 @@ CClientGame::~CClientGame()
// if a vehicle is destroyed while it explodes.
g_pGame->GetExplosionManager()->RemoveAllExplosions();

// Reset custom streaming memory size [possibly] set by the server...
g_pCore->SetCustomStreamingMemory(0);

// ...and restore the buffer size too
g_pGame->GetStreaming()->SetStreamingBufferSize(g_pClientGame->GetManager()->GetIMGManager()->GetLargestFileSizeBlocks());

// Reset camera shaking
g_pGame->GetCamera()->SetShakeForce(0.0f);

// Stop playing the continious sounds
// Stop playing the continuous sounds
// if the game was loaded. This is done by
// playing these special IDS.
if (m_bGameLoaded)
Expand Down Expand Up @@ -529,9 +535,6 @@ CClientGame::~CClientGame()
m_bBeingDeleted = false;

CStaticFunctionDefinitions::ResetAllSurfaceInfo();

// Reset custom streaming memory size [possibly] set by the server
g_pCore->SetCustomStreamingMemory(0);
}

/*
Expand Down
15 changes: 10 additions & 5 deletions Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp
Expand Up @@ -54,13 +54,16 @@ size_t EngineStreamingGetMemorySize() {
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;
return g_pGame->GetStreaming()->SetStreamingBufferSize(sizeBlocks);
} else {
return false;
}
}

void EngineStreamingRestoreBufferSize() {
g_pGame->GetStreaming()->SetStreamingBufferSize(g_pClientGame->GetManager()->GetIMGManager()->GetLargestFileSizeBlocks());
}

// Get current streaming buffer size
size_t EngineStreamingGetBufferSize() {
return g_pGame->GetStreaming()->GetStreamingBufferSize();
Expand Down Expand Up @@ -127,10 +130,11 @@ void CLuaEngineDefs::LoadFunctions()
{"engineStreamingGetUsedMemory", ArgumentParser<EngineStreamingGetUsedMemory>},
{"engineStreamingSetMemorySize", ArgumentParser<EngineStreamingSetMemorySize>},
{"engineStreamingGetMemorySize", ArgumentParser<EngineStreamingGetMemorySize>},
{"engineStreamingSetModelCacheLimits", ArgumentParser<EngineStreamingSetModelCacheLimits>},
{"engineStreamingRestoreMemorySize", ArgumentParser<EngineStreamingRestoreMemorySize>},
{"engineStreamingSetBufferSize", ArgumentParser<EngineStreamingSetBufferSize>},
{"engineStreamingGetBufferSize", ArgumentParser<EngineStreamingGetBufferSize>},
{"engineStreamingSetModelCacheLimits", ArgumentParser<EngineStreamingSetModelCacheLimits>},
{"engineStreamingRestoreBufferSize", ArgumentParser<EngineStreamingRestoreBufferSize>},

{"engineRequestTXD", ArgumentParser<EngineRequestTXD>},
{"engineFreeTXD", ArgumentParser<EngineFreeTXD>},
Expand Down Expand Up @@ -192,13 +196,14 @@ void CLuaEngineDefs::AddClass(lua_State* luaVM)
lua_classfunction(luaVM, "getUsedMemory", "engineStreamingGetUsedMemory");
lua_classfunction(luaVM, "setMemorySize", "engineStreamingSetMemorySize");
lua_classfunction(luaVM, "getMemorySize", "engineStreamingGetMemorySize");
lua_classfunction(luaVM, "setModelCacheLimits", "engineStreamingSetModelCacheLimits");
lua_classfunction(luaVM, "restoreMemorySize", "engineStreamingRestoreMemorySize");
lua_classfunction(luaVM, "getBufferSize", "engineStreamingGetBufferSize");
lua_classfunction(luaVM, "setBufferSize", "engineStreamingSetBufferSize");
lua_classfunction(luaVM, "setModelCacheLimits", "engineStreamingSetModelCacheLimits");
lua_classfunction(luaVM, "restoreBufferSize", "engineStreamingRestoreBufferSize");

lua_classvariable(luaVM, "memorySize", "engineStreamingSetMemorySize", "engineStreamingGetMemorySize");
lua_classvariable(luaVM, "bufferSize", "engineStreamingSetBufferSize", "engineStreamingGetMemorySize");
lua_classvariable(luaVM, "bufferSize", "engineStreamingSetBufferSize", "engineStreamingGetBufferSize");
lua_classvariable(luaVM, "usedMemory", NULL, "engineStreamingGetUsedMemory");
}
lua_registerstaticclass(luaVM, "EngineStreaming");
Expand Down
2 changes: 1 addition & 1 deletion Client/sdk/game/CStreaming.h
Expand Up @@ -42,7 +42,7 @@ class CStreaming
virtual unsigned char AddArchive(const char* szFilePath) = 0;
virtual void RemoveArchive(unsigned char ucArchiveID) = 0;
virtual void SetStreamingInfo(unsigned int id, unsigned char usStreamID, unsigned int uiOffset, unsigned short usSize, unsigned int uiNextInImg = -1) = 0;
virtual void SetStreamingBufferSize(uint32 uiSize) = 0;
virtual bool SetStreamingBufferSize(uint32 uiSize) = 0;
virtual uint32 GetStreamingBufferSize() = 0;
virtual void MakeSpaceFor(std::uint32_t memoryToCleanInBytes) = 0;
virtual std::uint32_t GetMemoryUsed() const = 0;
Expand Down

0 comments on commit 6c86ebb

Please sign in to comment.