Fixing lag compensation and make more smooth

This commit is contained in:
Vladislav Khorev committed 2026-02-05 09:00:54 +03:00
1 parent 82ca994fac
commit 7b1d9363a0
6 files changed
+159 -54

No files matched your search

+49 -26
View File
@@ -732,13 +732,13 @@ namespace ZL
// Биндим текстуру корабля один раз для всех удаленных игроков (оптимизация батчинга)
glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID());
auto now = std::chrono::system_clock::now();
/*auto now = std::chrono::system_clock::now();
//Apply server delay:
now -= std::chrono::milliseconds(CLIENT_DELAY);
latestRemotePlayers = networkClient->getRemotePlayers();
*/
// Если сервер прислал коробки, применяем их однократно вместо локальной генерации
if (!serverBoxesApplied && networkClient) {
auto sboxes = networkClient->getServerBoxes();
@@ -761,15 +761,9 @@ namespace ZL
}
// Итерируемся по актуальным данным из extrapolateRemotePlayers
for (auto const& [id, remotePlayer] : latestRemotePlayers) {
if (!remotePlayer.canFetchClientStateAtTime(now))
{
continue;
}
ClientState playerState = remotePlayer.fetchClientStateAtTime(now);
for (auto const& [id, remotePlayer] : remotePlayerStates) {
const ClientState& playerState = remotePlayer;
renderer.PushMatrix();
renderer.LoadIdentity();
@@ -809,18 +803,15 @@ namespace ZL
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Берем удаленных игроков
latestRemotePlayers = networkClient->getRemotePlayers();
//latestRemotePlayers = networkClient->getRemotePlayers();
auto now = std::chrono::system_clock::now();
now -= std::chrono::milliseconds(CLIENT_DELAY);
for (auto const& [id, remotePlayer] : latestRemotePlayers)
for (auto const& [id, remotePlayer] : remotePlayerStates)
{
if (!remotePlayer.canFetchClientStateAtTime(now))
continue;
ClientState st = remotePlayer.fetchClientStateAtTime(now);
const ClientState& st = remotePlayer;
// Позиция корабля в мире
Vector3f shipWorld = st.position;
@@ -861,6 +852,9 @@ namespace ZL
lastTickCount = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()
).count();
lastTickCount = (lastTickCount / 50)*50;
return;
}
@@ -869,6 +863,8 @@ namespace ZL
std::chrono::system_clock::now().time_since_epoch()
).count();
newTickCount = (newTickCount / 50) * 50;
if (newTickCount - lastTickCount > CONST_TIMER_INTERVAL) {
size_t delta = newTickCount - lastTickCount;
@@ -882,15 +878,7 @@ namespace ZL
sparkEmitter.update(static_cast<float>(delta));
planetObject.update(static_cast<float>(delta));
static float pingTimer = 0.0f;
pingTimer += delta;
if (pingTimer >= 1000.0f) {
std::string pingMsg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent();
networkClient->Send(pingMsg);
std::cout << "Sending: " << pingMsg << std::endl;
pingTimer = 0.0f;
}
//Handle input:
@@ -946,9 +934,44 @@ namespace ZL
std::cout << "Sending: " << msg << std::endl;
}
Environment::shipState.simulate_physics(delta);
long long leftoverDelta = delta;
while (leftoverDelta > 0)
{
long long miniDelta = 50;
Environment::shipState.simulate_physics(miniDelta);
leftoverDelta -= miniDelta;
}
Environment::inverseShipMatrix = Environment::shipState.rotation.inverse();
static float pingTimer = 0.0f;
pingTimer += delta;
if (pingTimer >= 1000.0f) {
std::string pingMsg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent();
networkClient->Send(pingMsg);
std::cout << "Sending: " << pingMsg << std::endl;
pingTimer = 0.0f;
}
auto latestRemotePlayers = networkClient->getRemotePlayers();
std::chrono::system_clock::time_point nowRounded{ std::chrono::milliseconds(newTickCount) };
for (auto const& [id, remotePlayer] : latestRemotePlayers) {
if (!remotePlayer.canFetchClientStateAtTime(nowRounded))
{
continue;
}
ClientState playerState = remotePlayer.fetchClientStateAtTime(nowRounded);
remotePlayerStates[id] = playerState;
}
for (auto& p : projectiles) {
if (p && p->isActive()) {
p->update(static_cast<float>(delta), renderer);
+2 -1
View File
@@ -73,7 +73,8 @@ namespace ZL {
std::vector<std::string> boxLabels;
std::unique_ptr<TextRenderer> textRenderer;
std::unordered_map<int, ClientStateInterval> latestRemotePlayers;
//std::unordered_map<int, ClientStateInterval> latestRemotePlayers;
std::unordered_map<int, ClientState> remotePlayerStates;
float newShipVelocity = 0;
+11 -1
View File
@@ -157,6 +157,16 @@ void ClientState::apply_lag_compensation(std::chrono::system_clock::time_point n
deltaMs = std::chrono::duration_cast<std::chrono::milliseconds>(nowTime - lastUpdateServerTime).count();
}
long long deltaMsLeftover = deltaMs;
while (deltaMsLeftover > 0)
{
long long miniDelta = 50;
simulate_physics(miniDelta);
deltaMsLeftover -= miniDelta;
}
/*
// 3. Защита от слишком больших скачков (Clamp)
// Если лаг более 500мс, ограничиваем его, чтобы избежать резких рывков
long long final_lag_ms = deltaMs;//min(deltaMs, 500ll);
@@ -165,7 +175,7 @@ void ClientState::apply_lag_compensation(std::chrono::system_clock::time_point n
// Доматываем симуляцию на величину задержки
// Мы предполагаем, что за это время параметры управления не менялись
simulate_physics(final_lag_ms);
}
}*/
}
void ClientState::handle_full_sync(const std::vector<std::string>& parts, int startFrom) {
+29
View File
@@ -202,6 +202,35 @@ namespace ZL {
}
}
if (msg.rfind("SNAPSHOT:", 0) == 0) {
auto mainParts = split(msg.substr(9), '|'); // Отсекаем "SNAPSHOT:" и делим по игрокам
if (mainParts.empty()) continue;
uint64_t serverTimestamp = std::stoull(mainParts[0]);
std::chrono::system_clock::time_point serverTime{ std::chrono::milliseconds(serverTimestamp) };
for (size_t i = 1; i < mainParts.size(); ++i) {
auto playerParts = split(mainParts[i], ':');
if (playerParts.size() < 15) continue; // ID + 14 полей ClientState
int rId = std::stoi(playerParts[0]);
if (rId == clientId) continue; // Свое состояние игрок знает лучше всех (Client Side Prediction)
ClientState remoteState;
remoteState.id = rId;
remoteState.lastUpdateServerTime = serverTime;
// Используем твой handle_full_sync, начиная со 2-го индекса (пропускаем ID в playerParts)
remoteState.handle_full_sync(playerParts, 1);
{
std::lock_guard<std::mutex> pLock(playersMutex);
remotePlayers[rId].add_state(remoteState);
}
}
continue;
}
}
}
void WebSocketClient::Send(const std::string& message) {