From 6893654cfcf0c92b8980ad8725a189b62f33578b Mon Sep 17 00:00:00 2001 From: phosit Date: Fri, 3 Apr 2026 18:38:13 +0200 Subject: [PATCH] Do the gamestate compression in the task-manager This reduces the stutter when a client joins. The decompression isn't put on the task manager. As the client would have to wait for that either way. Also a new polling loop would have to be introduced. The compression code is moved to the file transferer so all data send through it gits compressed. Refs: #4210 --- source/network/NetClient.cpp | 20 +++----------- source/network/NetFileTransfer.cpp | 33 +++++++++++++++++++----- source/network/NetFileTransfer.h | 2 ++ source/network/tests/test_FileTransfer.h | 16 +++++++++--- 4 files changed, 44 insertions(+), 27 deletions(-) diff --git a/source/network/NetClient.cpp b/source/network/NetClient.cpp index 4e53851613..6a47929da0 100644 --- a/source/network/NetClient.cpp +++ b/source/network/NetClient.cpp @@ -34,7 +34,6 @@ #include "network/StunClient.h" #include "ps/CLogger.h" #include "ps/CStr.h" -#include "ps/Compress.h" #include "ps/Game.h" #include "ps/Hashing.h" #include "ps/Profile.h" @@ -581,7 +580,7 @@ bool CNetClient::HandleMessage(CNetMessage* message) { CFileTransferRequestMessage* reqMessage = static_cast(message); - std::string uncompressedGameState{[&] + std::string gameState{[&] { if (static_cast(reqMessage->m_RequestType) == CNetFileTransferer::RequestType::LOADGAME) @@ -600,13 +599,8 @@ bool CNetClient::HandleMessage(CNetMessage* message) return stream.str(); }()}; - // Compress the content with zlib to save bandwidth - // (TODO: if this is still too large, compressing with e.g. LZMA works much better) - std::string compressedGameState; - CompressZLib(std::move(uncompressedGameState), compressedGameState, true); - m_Session->GetFileTransferer().StartResponse(reqMessage->m_RequestID, - std::move(compressedGameState)); + std::move(gameState)); return true; } @@ -625,10 +619,7 @@ void CNetClient::LoadFinished() // We're rejoining a game, and just finished loading the initial map, // so deserialize the saved game state now - std::string state; - DecompressZLib(m_JoinSyncBuffer, state, true); - - std::stringstream stream(state); + std::stringstream stream(m_JoinSyncBuffer); u32 turn; stream.read((char*)&turn, sizeof(turn)); @@ -857,10 +848,7 @@ bool CNetClient::OnSavedGameStart(CNetClient* client, CFsmEvent* e client->m_Session->GetFileTransferer().StartTask(CNetFileTransferer::RequestType::LOADGAME, [client, initAttribs](std::string buffer) { - std::string state; - DecompressZLib(buffer, state, true); - - client->StartGame(&*initAttribs, state); + client->StartGame(&*initAttribs, std::move(buffer)); }); return true; } diff --git a/source/network/NetFileTransfer.cpp b/source/network/NetFileTransfer.cpp index 06caf8cede..0e3e49de74 100644 --- a/source/network/NetFileTransfer.cpp +++ b/source/network/NetFileTransfer.cpp @@ -25,6 +25,8 @@ #include "network/NetMessage.h" #include "ps/CLogger.h" #include "ps/CStr.h" +#include "ps/Compress.h" +#include "ps/TaskManager.h" #include #include @@ -102,7 +104,9 @@ Status CNetFileTransferer::OnFileTransferData(const CFileTransferDataMessage& me { LOGMESSAGERENDER("Download completed"); - task.onComplete(std::move(task.buffer)); + std::string uncompressed; + DecompressZLib(task.buffer, uncompressed, true); + task.onComplete(std::move(uncompressed)); m_FileReceiveTasks.erase(it); return INFO::OK; } @@ -161,16 +165,18 @@ void CNetFileTransferer::StartResponse(u32 requestID, const std::string& data) { CNetFileSendTask task; task.requestID = requestID; - task.buffer = data; task.offset = 0; task.packetsInFlight = 0; task.maxWindowSize = DEFAULT_FILE_TRANSFER_WINDOW_SIZE; + task.task = {g_TaskManager, [data] + { + // Compress the content with zlib to save bandwidth + std::string compressedGameState; + CompressZLib(std::move(data), compressedGameState, true); + return compressedGameState; + }, Threading::TaskPriority::LOW}; - m_FileSendTasks[task.requestID] = task; - CFileTransferResponseMessage respMessage; - respMessage.m_RequestID = requestID; - respMessage.m_Length = task.buffer.size(); - m_SendMessage(&respMessage); + m_FileSendTasks.insert({task.requestID, std::move(task)}); } void CNetFileTransferer::Poll() @@ -181,6 +187,19 @@ void CNetFileTransferer::Poll() { CNetFileSendTask& task = p.second; + if (task.task.Valid()) + { + if (!task.task.IsDone()) + continue; + + task.buffer = std::exchange(task.task, {}).Get(); + + CFileTransferResponseMessage respMessage; + respMessage.m_RequestID = task.requestID; + respMessage.m_Length = task.buffer.size(); + m_SendMessage(&respMessage); + } + while (task.packetsInFlight < task.maxWindowSize && task.offset < task.buffer.size()) { CFileTransferDataMessage dataMessage; diff --git a/source/network/NetFileTransfer.h b/source/network/NetFileTransfer.h index 70c4127637..6b57b3dd3c 100644 --- a/source/network/NetFileTransfer.h +++ b/source/network/NetFileTransfer.h @@ -21,6 +21,7 @@ #include "lib/alignment.h" #include "lib/status.h" #include "lib/types.h" +#include "ps/Future.h" #include #include @@ -105,6 +106,7 @@ private: size_t offset; size_t maxWindowSize; size_t packetsInFlight; + Future task; }; std::function m_SendMessage; diff --git a/source/network/tests/test_FileTransfer.h b/source/network/tests/test_FileTransfer.h index 1753286d36..ab6db1ad0b 100644 --- a/source/network/tests/test_FileTransfer.h +++ b/source/network/tests/test_FileTransfer.h @@ -20,13 +20,17 @@ #include "network/NetFileTransfer.h" #include "network/NetMessage.h" +#include #include #include #include #include #include +#include #include +using namespace std::literals; + namespace { constexpr const char* MESSAGECONTENT{"Some example message content"}; @@ -102,14 +106,18 @@ public: CheckSizes(client.queues, 1, 0, 0, 0); server.transferer.StartResponse(client.queues.requests.at(0).m_RequestID, MESSAGECONTENT); - CheckSizes(server.queues, 0, 1, 0, 0); + CheckSizes(server.queues, 0, 0, 0, 0); + + while (server.queues.responses.size() == 0) + { + std::this_thread::sleep_for(10ms); + server.transferer.Poll(); + } + CheckSizes(server.queues, 0, 1, 1, 0); client.transferer.HandleMessageReceive(server.queues.responses.at(0)); CheckSizes(client.queues, 1, 0, 0, 0); - server.transferer.Poll(); - CheckSizes(server.queues, 0, 1, 1, 0); - server.transferer.Poll(); // If `MESSAGECONTENT` would be longer another message would be sent. CheckSizes(server.queues, 0, 1, 1, 0);