#pragma once #include "IGameServer.h" #include "InternalGameServer.h" #include "NetworkProtocol.h" #include #include #include namespace FRG { class RemoteGameServerHost; class WebsocketGameClient final : public IGameServer { public: WebsocketGameClient( std::string host = "127.0.0.1", std::string port = "8080", std::string path = "/"); ~WebsocketGameClient(); WebsocketGameClient(const WebsocketGameClient&) = delete; WebsocketGameClient& operator=(const WebsocketGameClient&) = delete; std::shared_ptr snapshot() const override; const std::string& localPlayerId() const override; void submit(const GameCommand& command) override; std::vector drainEvents() override; void update(std::int64_t deltaMs) override; void save(nlohmann::json& out) const override; void load(const nlohmann::json& in) override; bool connected() const; bool connectionFailed() const; bool initialized() const { return initialized_; } bool rejected() const { return rejected_; } private: friend class RemoteGameServerHost; struct CompletedSimulationTick { std::string locationId; LocationSimulationEvents events; }; std::vector takeCompletedSimulationTicks(); void expectCompatibility(std::string fingerprint) { expectedCompatibilityFingerprint_ = std::move(fingerprint); } class Impl; InternalGameServer replica_; std::unique_ptr impl_; std::map pendingTicks_; std::vector completedSimulationTicks_; std::vector pendingEvents_; std::uint64_t nextExpectedTick_ = 0; std::uint64_t nextClientSequence_ = 1; std::string compatibilityFingerprint_; std::string expectedCompatibilityFingerprint_; bool initialized_ = false; bool rejected_ = false; bool loggedFirstTick_ = false; }; } // namespace FRG