fill client holes (lockstep)

This commit is contained in:
2025-08-07 10:53:00 +02:00
parent c813c49707
commit ba84864b6a
9 changed files with 95 additions and 22 deletions

View File

@@ -49,8 +49,8 @@ class ClientHandler : public td::protocol::PacketHandler {
m_Simulation.Handle(a_LockStep);
}
void Handle(const td::protocol::packets::PredictCommandPacket& a_Predict) {
m_Simulation.Handle(a_Predict);
void Handle(const td::protocol::packets::LockStepResponsePacket& a_LockStep) {
m_Simulation.Handle(a_LockStep);
}
};
@@ -125,6 +125,10 @@ int main(int argc, char** argv) {
td::sim::ClientSimulation simulation(*clientWorld, td::STEP_TIME);
ClientHandler clientHandler(simulation);
simulation.OnMissingLockSteps.Connect([&fakeSocket](const std::vector<td::StepTime>& a_MissingSteps){
fakeSocket->OnReceive(0, td::protocol::packets::LockStepRequestPacket(a_MissingSteps));
});
// temporary tests
display.OnKeyDown.Connect([&fakeSocket](SDL_Keycode key) {
if (key == SDLK_A) {
@@ -134,6 +138,7 @@ int main(int argc, char** argv) {
}
});
// make a fake player join
fakeSocket->ConnectFakePeer(0);
// packets from the server to the client

View File

@@ -20,5 +20,9 @@ void GameStateHandler::Handle(const protocol::packets::PlaceTowerPacket& a_Packe
m_GameState.m_Simulation.Handle(place);
}
void GameStateHandler::Handle(const protocol::packets::LockStepRequestPacket& a_Packet) {
m_GameState.SendPacket(m_PlayerId, m_GameState.m_Simulation.GetResponse(a_Packet));
}
} // namespace server
} // namespace td

View File

@@ -4,6 +4,8 @@
#include <iostream>
// TODO: mutex this bad boy
namespace td {
namespace sim {
@@ -37,9 +39,7 @@ ClientSimulation::ClientSimulation(game::World& a_World, std::uint64_t a_StepTim
m_LastTime(GetTime()),
m_CurrentStep(0),
m_LastSnapshot(std::make_shared<WorldSnapshot>()),
m_LastValidStep(0) {
// Step();
}
m_LastValidStep(0) {}
float ClientSimulation::Update() {
// TODO: handle freezes (m_CurrentTime > 2 * m_StepTime)
@@ -52,15 +52,20 @@ float ClientSimulation::Update() {
return (float)m_CurrentTime / (float)m_StepTime;
}
void ClientSimulation::Step() {
bool ClientSimulation::Step() {
const auto& step = m_History[m_CurrentStep];
if (step.has_value()) {
m_LastSnapshot = m_World.Tick(step.value(), FpFloat(m_StepTime) / FpFloat(1000));
m_LastValidStep = m_CurrentStep;
auto snapshot = m_World.Tick(step.value(), FpFloat(m_StepTime) / FpFloat(1000));
if (m_LastValidStep + 1 == m_CurrentStep) {
m_LastValidStep = m_CurrentStep;
m_LastSnapshot = snapshot;
}
} else {
m_World.Tick(EMPTY_LOCKSTEP, FpFloat(m_StepTime) / FpFloat(1000));
std::cout << "Empty tick (" << m_CurrentStep << ") !\n";
}
m_CurrentStep++;
return step.has_value();
}
void ClientSimulation::Handle(const protocol::packets::LockStepsPacket& a_LockSteps) {
@@ -68,16 +73,32 @@ void ClientSimulation::Handle(const protocol::packets::LockStepsPacket& a_LockSt
for (std::size_t i = 0; i < LOCKSTEP_BUFFER_SIZE; i++) {
m_History[a_LockSteps->m_FirstFrameNumber + i] = steps[i];
}
// to be in the state [0-1]
if (a_LockSteps->m_FirstFrameNumber == 0)
Step();
FastReplay();
}
void ClientSimulation::Handle(const protocol::packets::PredictCommandPacket& a_Predict) {}
void ClientSimulation::FastForward(std::size_t a_Count) {
for (std::size_t i = 0; i < a_Count; i++) {
Step();
void ClientSimulation::Handle(const protocol::packets::LockStepResponsePacket& a_LockSteps) {
for (const auto& [stepTime, lockStep] : a_LockSteps->m_Steps) {
m_History[stepTime] = lockStep;
}
std::cout << "Was behind " << a_Count << " ticks !\n";
FastReplay();
}
std::size_t ClientSimulation::FastForward(std::size_t a_Count) {
std::size_t stepCount;
bool hasMissingStep = false;
for (std::size_t i = 0; i < a_Count; i++) {
if (!Step() && !hasMissingStep) {
hasMissingStep = true;
stepCount = i + 1;
}
}
std::cout << "Was behind " << (hasMissingStep ? stepCount : a_Count) << " ticks !\n";
return hasMissingStep ? stepCount : a_Count;
}
void ClientSimulation::FastReplay() {
@@ -86,11 +107,21 @@ void ClientSimulation::FastReplay() {
m_World.ResetSnapshots(m_LastSnapshot, m_LastSnapshot);
// TODO: cover holes
const std::size_t stepCount = m_CurrentStep - m_LastValidStep;
m_CurrentStep = m_LastValidStep;
FastForward(stepCount);
if (FastForward(stepCount) == stepCount)
return;
std::vector<StepTime> missingSteps;
missingSteps.reserve(stepCount);
for (StepTime step = m_LastValidStep + 1; step < m_CurrentStep; step++) {
if (!m_History[step].has_value())
missingSteps.push_back(step);
}
OnMissingLockSteps(missingSteps);
}
} // namespace sim

View File

@@ -36,5 +36,17 @@ void ServerSimulation::Handle(const protocol::commands::PlaceTowerCommand& a_Pla
AddToCommandHistory(m_History[m_CurrentTime + LOCKSTEP_BUFFER_SIZE], a_PlaceTower);
}
protocol::packets::LockStepResponsePacket ServerSimulation::GetResponse(
const protocol::packets::LockStepRequestPacket& a_Missing) const {
std::map<StepTime, protocol::LockStep> result;
for (StepTime step : a_Missing->m_Missing) {
result.emplace(step, m_History[step]);
}
return {result};
}
} // namespace sim
} // namespace td