space-game001/src/network/ClientState.cpp
Vladislav Khorev 1a7e424085 Major clean up
2026-01-18 13:13:25 +03:00

225 lines
6.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "ClientState.h"
void ClientState::simulate_physics(size_t delta) {
if (discreteMag > 0.01f)
{
float rad = static_cast<float>(discreteAngle) * static_cast<float>(M_PI) / 180.0f;
// Целевая угловая скорость (дискретная сила определяет модуль вектора)
// Вектор {cos, sin, 0} дает нам направление отклонения джойстика
Eigen::Vector3f targetAngularVelDir(sinf(rad), cosf(rad), 0.0f);
Eigen::Vector3f targetAngularVelocity = targetAngularVelDir * discreteMag;
Eigen::Vector3f diffVel = targetAngularVelocity - currentAngularVelocity;
float diffLen = diffVel.norm();
if (diffLen > 0.0001f) {
// Вычисляем, на сколько мы можем изменить скорость в этом кадре
float maxChange = ANGULAR_ACCEL * static_cast<float>(delta);
if (diffLen <= maxChange) {
// Если до цели осталось меньше, чем шаг ускорения — просто прыгаем в цель
currentAngularVelocity = targetAngularVelocity;
}
else {
// Линейно двигаемся в сторону целевого вектора
currentAngularVelocity += (diffVel / diffLen) * maxChange;
}
}
}
else
{
float currentSpeed = currentAngularVelocity.norm();
if (currentSpeed > 0.0001f) {
float drop = ANGULAR_ACCEL * static_cast<float>(delta);
if (currentSpeed <= drop) {
currentAngularVelocity = Eigen::Vector3f::Zero();
}
else {
// Уменьшаем модуль вектора, сохраняя направление
currentAngularVelocity -= (currentAngularVelocity / currentSpeed) * drop;
}
}
}
float speedScale = currentAngularVelocity.norm();
if (speedScale > 0.0001f) {
// Коэффициент чувствительности вращения
float deltaAlpha = speedScale * static_cast<float>(delta) * ROTATION_SENSITIVITY;
Eigen::Vector3f axis = currentAngularVelocity.normalized();
Eigen::Quaternionf rotateQuat(Eigen::AngleAxisf(deltaAlpha, axis));
rotation = rotation * rotateQuat.toRotationMatrix();
}
// 4. Линейное изменение линейной скорости
float shipDesiredVelocity = selectedVelocity * 100.f;
if (velocity < shipDesiredVelocity)
{
velocity += delta * SHIP_ACCEL;
if (velocity > shipDesiredVelocity)
{
velocity = shipDesiredVelocity;
}
}
else if (velocity > shipDesiredVelocity)
{
velocity -= delta * SHIP_ACCEL;
if (velocity < shipDesiredVelocity)
{
velocity = shipDesiredVelocity;
}
}
if (fabs(velocity) > 0.01f)
{
Eigen::Vector3f velocityDirection = { 0,0, -velocity * delta / 1000.f };
Eigen::Vector3f velocityDirectionAdjusted = rotation * velocityDirection;
position = position + velocityDirectionAdjusted;
}
}
void ClientState::apply_lag_compensation(std::chrono::system_clock::time_point nowTime) {
// 2. Вычисляем задержку
long long deltaMs = 0;
if (nowTime > lastUpdateServerTime) {
deltaMs = std::chrono::duration_cast<std::chrono::milliseconds>(nowTime - lastUpdateServerTime).count();
}
// 3. Защита от слишком больших скачков (Clamp)
// Если лаг более 500мс, ограничиваем его, чтобы избежать резких рывков
long long final_lag_ms = deltaMs;//min(deltaMs, 500ll);
if (final_lag_ms > 0) {
// Доматываем симуляцию на величину задержки
// Мы предполагаем, что за это время параметры управления не менялись
simulate_physics(final_lag_ms);
}
}
void ClientState::handle_full_sync(const std::vector<std::string>& parts, int startFrom) {
// Позиция
position = { std::stof(parts[startFrom]), std::stof(parts[startFrom + 1]), std::stof(parts[startFrom + 2]) };
Eigen::Quaternionf q(
std::stof(parts[startFrom + 3]),
std::stof(parts[startFrom + 4]),
std::stof(parts[startFrom + 5]),
std::stof(parts[startFrom + 6]));
rotation = q.toRotationMatrix();
currentAngularVelocity = Eigen::Vector3f{
std::stof(parts[startFrom + 7]),
std::stof(parts[startFrom + 8]),
std::stof(parts[startFrom + 9]) };
velocity = std::stof(parts[startFrom + 10]);
selectedVelocity = std::stoi(parts[startFrom + 11]);
discreteMag = std::stof(parts[startFrom + 12]);
discreteAngle = std::stoi(parts[startFrom + 13]);
}
std::string ClientState::formPingMessageContent()
{
Eigen::Quaternionf q(rotation);
std::string pingMsg = std::to_string(position.x()) + ":"
+ std::to_string(position.y()) + ":"
+ std::to_string(position.z()) + ":"
+ std::to_string(q.w()) + ":"
+ std::to_string(q.x()) + ":"
+ std::to_string(q.y()) + ":"
+ std::to_string(q.z()) + ":"
+ std::to_string(currentAngularVelocity.x()) + ":"
+ std::to_string(currentAngularVelocity.y()) + ":"
+ std::to_string(currentAngularVelocity.z()) + ":"
+ std::to_string(velocity) + ":"
+ std::to_string(selectedVelocity) + ":"
+ std::to_string(discreteMag) + ":" // Используем те же static переменные из блока ROT
+ std::to_string(discreteAngle);
return pingMsg;
}
void ClientStateInterval::add_state(const ClientState& state)
{
auto nowTime = std::chrono::system_clock::now();
if (timedStates.size() > 0 && timedStates[timedStates.size() - 1].lastUpdateServerTime == state.lastUpdateServerTime)
{
timedStates[timedStates.size() - 1] = state;
}
else
{
timedStates.push_back(state);
}
auto cutoff_time = nowTime - std::chrono::milliseconds(CUTOFF_TIME);
while (timedStates.size() > 0 && timedStates[0].lastUpdateServerTime < cutoff_time)
{
timedStates.erase(timedStates.begin());
}
}
bool ClientStateInterval::canFetchClientStateAtTime(std::chrono::system_clock::time_point targetTime) const
{
if (timedStates.empty())
{
return false;
}
if (timedStates[0].lastUpdateServerTime > targetTime)
{
return false;
}
return true;
}
ClientState ClientStateInterval::fetchClientStateAtTime(std::chrono::system_clock::time_point targetTime) const {
ClientState closestState;
if (timedStates.empty())
{
throw std::runtime_error("No timed client states available");
return closestState;
}
if (timedStates[0].lastUpdateServerTime > targetTime)
{
throw std::runtime_error("Found time but it is in future");
return closestState;
}
if (timedStates.size() == 1)
{
closestState = timedStates[0];
closestState.apply_lag_compensation(targetTime);
return closestState;
}
for (size_t i = 0; i < timedStates.size() - 1; ++i)
{
const auto& earlierState = timedStates[i];
const auto& laterState = timedStates[i + 1];
if (earlierState.lastUpdateServerTime <= targetTime && laterState.lastUpdateServerTime >= targetTime)
{
closestState = earlierState;
closestState.apply_lag_compensation(targetTime);
return closestState;
}
}
closestState = timedStates[timedStates.size() - 1];
closestState.apply_lag_compensation(targetTime);
return closestState;
}