Do the gamestate compression in the task-manager
Some checks failed
checkrefs / lfscheck (push) Has been cancelled
checkrefs / checkrefs (push) Has been cancelled
lint / cppcheck (push) Has been cancelled
lint / copyright (push) Has been cancelled
lint / jenkinsfiles (push) Has been cancelled
pre-commit / build (push) Has been cancelled

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
This commit is contained in:
phosit 2026-04-03 18:38:13 +02:00
parent 6a3da535f3
commit 6893654cfc
No known key found for this signature in database
GPG key ID: C9430B600671C268
4 changed files with 44 additions and 27 deletions

View file

@ -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<CFileTransferRequestMessage*>(message);
std::string uncompressedGameState{[&]
std::string gameState{[&]
{
if (static_cast<CNetFileTransferer::RequestType>(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<CNetMessage*>* 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;
}

View file

@ -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 <algorithm>
#include <utility>
@ -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;

View file

@ -21,6 +21,7 @@
#include "lib/alignment.h"
#include "lib/status.h"
#include "lib/types.h"
#include "ps/Future.h"
#include <cstddef>
#include <functional>
@ -105,6 +106,7 @@ private:
size_t offset;
size_t maxWindowSize;
size_t packetsInFlight;
Future<std::string> task;
};
std::function<bool(const CNetMessage* message)> m_SendMessage;

View file

@ -20,13 +20,17 @@
#include "network/NetFileTransfer.h"
#include "network/NetMessage.h"
#include <chrono>
#include <cstddef>
#include <functional>
#include <initializer_list>
#include <string>
#include <utility>
#include <thread>
#include <vector>
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);