Add plugin receive loop & remote player state

Add a networking receive loop and in-plugin remote-player storage. Introduces F4TRemotePlayerState (header + implementation) to track assigned playerId and remote player snapshots with thread-safe access. Expands F4TNetworking to start/stop a background receive thread, parse newline-separated JSON packets (welcome, transform, disconnect), validate fields, update remote state, throttle logs, and handle socket/thread synchronization. Add nlohmann_json to xmake and plugin build. Update docs and dev log to reflect the new receive behavior and current prototype scope.
This commit is contained in:
2026-05-31 20:10:41 +12:00
parent d724d7404c
commit 62635f4226
10 changed files with 581 additions and 70 deletions
+73
View File
@@ -0,0 +1,73 @@
#include "pch.h"
#include "F4TRemotePlayerState.h"
#include <mutex>
#include <optional>
#include <unordered_map>
#include <vector>
namespace
{
std::mutex g_stateMutex;
std::optional<std::uint32_t> g_assignedPlayerId;
std::unordered_map<std::uint32_t, F4T::RemotePlayerState::RemotePlayerState> g_remotePlayers;
}
namespace F4T::RemotePlayerState
{
void SetAssignedPlayerId(std::uint32_t a_playerId)
{
const std::scoped_lock lock(g_stateMutex);
g_assignedPlayerId = a_playerId;
}
std::optional<std::uint32_t> GetAssignedPlayerId()
{
const std::scoped_lock lock(g_stateMutex);
return g_assignedPlayerId;
}
bool IsAssignedPlayerId(std::uint32_t a_playerId)
{
const std::scoped_lock lock(g_stateMutex);
return g_assignedPlayerId.has_value() && *g_assignedPlayerId == a_playerId;
}
void ClearAssignedPlayerId()
{
const std::scoped_lock lock(g_stateMutex);
g_assignedPlayerId.reset();
}
void UpdateRemotePlayer(RemotePlayerState a_state)
{
const std::scoped_lock lock(g_stateMutex);
g_remotePlayers[a_state.playerId] = std::move(a_state);
}
bool RemoveRemotePlayer(std::uint32_t a_playerId)
{
const std::scoped_lock lock(g_stateMutex);
return g_remotePlayers.erase(a_playerId) > 0;
}
void ClearRemotePlayers()
{
const std::scoped_lock lock(g_stateMutex);
g_remotePlayers.clear();
}
std::vector<RemotePlayerState> GetRemotePlayerSnapshot()
{
const std::scoped_lock lock(g_stateMutex);
std::vector<RemotePlayerState> snapshot;
snapshot.reserve(g_remotePlayers.size());
for (const auto& [_, player] : g_remotePlayers) {
snapshot.push_back(player);
}
return snapshot;
}
}