send map when arriving late

This commit is contained in:
2025-08-22 12:24:58 +02:00
parent 688b6e93ea
commit 5b6254c690
12 changed files with 52 additions and 16 deletions

View File

@@ -14,7 +14,7 @@ class GameState : public ClientState {
float m_CurrentLerp; float m_CurrentLerp;
public: public:
GameState(Client& a_Client, const game::WorldPtr& a_World, std::uint64_t a_StepTime); GameState(Client& a_Client, const game::WorldPtr& a_World, std::uint64_t a_StepTime, const std::vector<protocol::LockStep> a_FirstSteps);
~GameState() {} ~GameState() {}
virtual void Update(float a_Delta) override; virtual void Update(float a_Delta) override;

View File

@@ -18,6 +18,7 @@ class LobbyState : public ClientState {
virtual void Handle(const protocol::packets::WorldHeaderPacket& a_Packet) override; virtual void Handle(const protocol::packets::WorldHeaderPacket& a_Packet) override;
virtual void Handle(const protocol::packets::WorldDataPacket& a_Packet) override; virtual void Handle(const protocol::packets::WorldDataPacket& a_Packet) override;
virtual void Handle(const protocol::packets::BeginGamePacket& a_Packet) override;
}; };
} // namespace client } // namespace client

View File

@@ -22,6 +22,8 @@ class GameState : public ServerState {
virtual void HandlePacket(PlayerID a_Id, const protocol::PacketBase& a_Packet) override; virtual void HandlePacket(PlayerID a_Id, const protocol::PacketBase& a_Packet) override;
virtual void Update(float a_Delta) override; virtual void Update(float a_Delta) override;
virtual void OnPlayerJoin(PlayerID a_Id, const td::PlayerInfo& a_Info) override;
friend class GameStateHandler; friend class GameStateHandler;
}; };

View File

@@ -67,8 +67,6 @@ struct ChatMessage {
std::string m_Text; std::string m_Text;
}; };
// TODO: handle players joining in the first second
struct BeginGame { struct BeginGame {
std::vector<PlayerInfo> m_BlueTeam; std::vector<PlayerInfo> m_BlueTeam;
std::vector<PlayerInfo> m_RedTeam; std::vector<PlayerInfo> m_RedTeam;

View File

@@ -39,7 +39,7 @@ class ClientSimulation : public protocol::PacketHandler {
* \brief Live update constructor (continuous game updates) * \brief Live update constructor (continuous game updates)
* \param a_StepTime in ms * \param a_StepTime in ms
*/ */
ClientSimulation(std::shared_ptr<game::World> a_World, std::uint64_t a_StepTime); ClientSimulation(std::shared_ptr<game::World> a_World, std::uint64_t a_StepTime, const std::vector<protocol::LockStep>& a_FirstSteps);
/** /**
* \return the progress [0-1] between two steps * \return the progress [0-1] between two steps

View File

@@ -16,7 +16,7 @@ class ServerSimulation : public protocol::CommandHandler {
game::World& m_World; game::World& m_World;
std::uint64_t m_StepTime; std::uint64_t m_StepTime;
std::uint64_t m_CurrentTime; std::uint64_t m_CurrentTime;
std::vector<td::protocol::LockStep> m_History; std::vector<protocol::LockStep> m_History;
using protocol::CommandHandler::Handle; using protocol::CommandHandler::Handle;
@@ -27,6 +27,8 @@ class ServerSimulation : public protocol::CommandHandler {
protocol::packets::LockStepsPacket MakePacket(); protocol::packets::LockStepsPacket MakePacket();
std::vector<protocol::LockStep> GetFirstLocksteps();
// no checks are done ! // no checks are done !
virtual void Handle(const protocol::commands::SpawnTroopCommand& a_SpawnTroop) override; virtual void Handle(const protocol::commands::SpawnTroopCommand& a_SpawnTroop) override;

View File

@@ -3,8 +3,8 @@
namespace td { namespace td {
namespace client { namespace client {
GameState::GameState(Client& a_Client, const std::shared_ptr<game::World>& a_World, std::uint64_t a_StepTime) : GameState::GameState(Client& a_Client, const std::shared_ptr<game::World>& a_World, std::uint64_t a_StepTime, const std::vector<protocol::LockStep> a_FirstSteps) :
ClientState(a_Client), m_World(a_World), m_Simulation(a_World, a_StepTime) { ClientState(a_Client), m_World(a_World), m_Simulation(a_World, a_StepTime, a_FirstSteps) {
m_Simulation.OnMissingLockSteps.Connect([this](const std::vector<td::StepTime>& a_MissingSteps) { m_Simulation.OnMissingLockSteps.Connect([this](const std::vector<td::StepTime>& a_MissingSteps) {
SendPacket(protocol::packets::LockStepRequestPacket(a_MissingSteps)); SendPacket(protocol::packets::LockStepRequestPacket(a_MissingSteps));
}); });

View File

@@ -15,7 +15,10 @@ void LobbyState::Handle(const protocol::packets::WorldHeaderPacket& a_Packet) {
void LobbyState::Handle(const protocol::packets::WorldDataPacket& a_Packet) { void LobbyState::Handle(const protocol::packets::WorldDataPacket& a_Packet) {
m_World->LoadMap(*a_Packet); m_World->LoadMap(*a_Packet);
ChangeState<GameState>(m_World, STEP_TIME); }
void LobbyState::Handle(const protocol::packets::BeginGamePacket& a_Packet) {
ChangeState<GameState>(m_World, STEP_TIME, a_Packet->m_FirstLocksteps);
} }
void LobbyState::Update(float a_Delta) {} void LobbyState::Update(float a_Delta) {}

View File

@@ -7,10 +7,12 @@
namespace td { namespace td {
namespace server { namespace server {
GameState::GameState(Server& a_Server, const std::shared_ptr<game::World>& a_World) : ServerState(a_Server), m_World(a_World), m_Simulation(*m_World, STEP_TIME), m_Time(0) { GameState::GameState(Server& a_Server, const std::shared_ptr<game::World>& a_World) :
ServerState(a_Server), m_World(a_World), m_Simulation(*m_World, STEP_TIME), m_Time(0) {
std::cout << "[Server] Switched to Game state !\n"; std::cout << "[Server] Switched to Game state !\n";
BroadcastPacket(a_World->GetPacketHeader()); BroadcastPacket(a_World->GetPacketHeader());
BroadcastPacket(a_World->GetPacketData()); BroadcastPacket(a_World->GetPacketData());
BroadcastPacket(protocol::packets::BeginGamePacket());
BroadcastPacket(m_Simulation.MakePacket()); BroadcastPacket(m_Simulation.MakePacket());
} }
@@ -30,5 +32,16 @@ void GameState::Update(float a_Delta) {
} }
} }
void GameState::OnPlayerJoin(PlayerID a_Id, const td::PlayerInfo& a_Info) {
SendPacket(a_Id, m_World->GetPacketHeader());
SendPacket(a_Id, m_World->GetPacketData());
// TODO: real teams
std::vector<PlayerInfo> team;
std::vector<protocol::LockStep> locksteps = m_Simulation.GetFirstLocksteps();
BroadcastPacket(protocol::packets::BeginGamePacket(team, team, locksteps));
}
} // namespace server } // namespace server
} // namespace td } // namespace td

View File

@@ -47,12 +47,11 @@ DebugWorldState::DebugWorldState(Display& a_Display) : DisplayState(a_Display) {
}); });
m_Client->ChangeState<client::LoggingState>("Player0"); m_Client->ChangeState<client::LoggingState>("Player0");
std::cout << "Switched to login!\n";
// // client2 // client2
// auto clientFakeSocket2 = client::FakeSocket::Connect(serverFakeSocket); auto clientFakeSocket2 = client::FakeSocket::Connect(serverFakeSocket);
// m_Client2 = std::make_unique<client::Client>(clientFakeSocket2, "Player1"); m_Client2 = std::make_unique<client::Client>(clientFakeSocket2, "Player1");
// m_Client2->ChangeState<client::LoggingState>("Player1"); m_Client2->ChangeState<client::LoggingState>("Player1");
// camera // camera
m_Camera.SetCamPos({77, 7, 13}); m_Camera.SetCamPos({77, 7, 13});

View File

@@ -30,14 +30,22 @@ ClientSimulation::ClientSimulation(std::shared_ptr<game::World> a_World, GameHis
Step(); Step();
} }
ClientSimulation::ClientSimulation(std::shared_ptr<game::World> a_World, std::uint64_t a_StepTime) : ClientSimulation::ClientSimulation(
std::shared_ptr<game::World> a_World, std::uint64_t a_StepTime, const std::vector<protocol::LockStep>& a_FirstSteps) :
m_StepTime(a_StepTime), m_StepTime(a_StepTime),
m_World(a_World), m_World(a_World),
m_History(std::numeric_limits<StepTime>::max()), m_History(std::numeric_limits<StepTime>::max()),
m_CurrentTime(0), m_CurrentTime(0),
m_CurrentStep(0), m_CurrentStep(0),
m_LastSnapshot(std::make_shared<WorldSnapshot>()), m_LastSnapshot(std::make_shared<WorldSnapshot>()),
m_LastValidStep(0) {} m_LastValidStep(0) {
if (!a_FirstSteps.empty()) {
for (std::size_t i = 0; i < a_FirstSteps.size(); i++) {
m_History[i] = a_FirstSteps[i];
}
FastForward(a_FirstSteps.size());
}
}
float ClientSimulation::Update(float a_Delta) { float ClientSimulation::Update(float a_Delta) {
// TODO: handle freezes (m_CurrentTime > 2 * m_StepTime) // TODO: handle freezes (m_CurrentTime > 2 * m_StepTime)

View File

@@ -47,6 +47,16 @@ protocol::packets::LockStepResponsePacket ServerSimulation::GetResponse(
return {result}; return {result};
} }
std::vector<protocol::LockStep> ServerSimulation::GetFirstLocksteps() {
std::vector<protocol::LockStep> result;
if (m_CurrentTime <= LOCKSTEP_BUFFER_SIZE)
return result;
result.reserve(m_CurrentTime);
result.insert(result.begin(), m_History.begin(), m_History.begin() + m_CurrentTime);
return result;
}
} // namespace sim } // namespace sim
} // namespace td } // namespace td