diff --git a/src/network/Message.h b/src/network/Message.h index 852c6dc..60f7b5a 100644 --- a/src/network/Message.h +++ b/src/network/Message.h @@ -13,6 +13,7 @@ #include #include +#include namespace UNO::NETWORK { @@ -29,12 +30,19 @@ namespace UNO::NETWORK { std::vector cards; }; + struct PlayerPublicState { + std::string name; + size_t remainingCardCount; + bool isUno; + }; + struct PlayCardPayload { GAME::Card card; }; struct InitGamePayload { size_t playerId; + std::vector players; GAME::DiscardPile discardPile; std::multiset handCard; size_t currentPlayerIndex; diff --git a/src/network/MessageSerializer.cpp b/src/network/MessageSerializer.cpp index a929456..be764b5 100644 --- a/src/network/MessageSerializer.cpp +++ b/src/network/MessageSerializer.cpp @@ -28,6 +28,20 @@ namespace UNO::NETWORK { return serializeCards(cards.begin(), cards.end()); } + nlohmann::json MessageSerializer::serializePlayerPublicState(const PlayerPublicState &state) + { + return {{"name", state.name}, {"remaining_cards", state.remainingCardCount}, {"is_uno", state.isUno}}; + } + + nlohmann::json MessageSerializer::serializePlayerPublicStates(const std::vector &states) + { + nlohmann::json result = nlohmann::json::array(); + for (const auto &state : states) { + result.push_back(serializePlayerPublicState(state)); + } + return result; + } + nlohmann::json MessageSerializer::serializePayload(const std::monostate &payload) { return nullptr; @@ -56,6 +70,7 @@ namespace UNO::NETWORK { nlohmann::json MessageSerializer::serializePayload(const InitGamePayload &payload) { return {{"player_id", payload.playerId}, + {"players", serializePlayerPublicStates(payload.players)}, {"discard_pile", serializeDiscardPile(payload.discardPile)}, {"hand_card", serializeCards(payload.handCard.begin(), payload.handCard.end())}, {"current_player", payload.currentPlayerIndex}}; @@ -215,6 +230,41 @@ namespace UNO::NETWORK { return res; } + PlayerPublicState MessageSerializer::deserializePlayerPublicState(const nlohmann::json &payload) + { + try { + if (payload.is_object() == false) { + throw std::invalid_argument("Invalid player public state: expected JSON object"); + } + if (payload.at("name").is_string() == false) { + throw std::invalid_argument("Invalid 'name' field in player public state: expected string"); + } + if (payload.at("remaining_cards").is_number_unsigned() == false) { + throw std::invalid_argument("Invalid 'remaining_cards' field in player public state: expected unsigned integer"); + } + if (payload.at("is_uno").is_boolean() == false) { + throw std::invalid_argument("Invalid 'is_uno' field in player public state: expected boolean"); + } + return {payload.at("name"), payload.at("remaining_cards"), payload.at("is_uno")}; + } + catch (const nlohmann::json::out_of_range &) { + throw std::invalid_argument("Missing required field in player public state: expected 'name', 'remaining_cards', 'is_uno'"); + } + } + + std::vector MessageSerializer::deserializePlayerPublicStates(const nlohmann::json &payload) + { + if (payload.is_array() == false) { + throw std::invalid_argument("Invalid players field in INIT_GAME payload: expected JSON array"); + } + + std::vector players; + for (const auto &entry : payload) { + players.push_back(deserializePlayerPublicState(entry)); + } + return players; + } + std::monostate MessageSerializer::deserializeEmptyPayload(const nlohmann::json &payload) { if (payload.is_null() == false) { @@ -299,13 +349,14 @@ namespace UNO::NETWORK { throw std::invalid_argument("Invalid 'current_player' field in INIT_GAME payload: expected unsigned integer"); } return {payload.at("player_id"), + deserializePlayerPublicStates(payload.at("players")), deserializeDiscardPile(payload.at("discard_pile")), deserializeHandCard(payload.at("hand_card")), payload.at("current_player")}; } catch (const nlohmann::json::out_of_range &) { throw std::invalid_argument( - "Missing required field in INIT_GAME payload: expected 'discard_pile', 'hand_card', and 'current_player'"); + "Missing required field in INIT_GAME payload: expected 'players', 'discard_pile', 'hand_card', and 'current_player'"); } } @@ -415,4 +466,4 @@ namespace UNO::NETWORK { } } -} // namespace UNO::NETWORK \ No newline at end of file +} // namespace UNO::NETWORK diff --git a/src/network/MessageSerializer.h b/src/network/MessageSerializer.h index 1dca8a3..da3e962 100644 --- a/src/network/MessageSerializer.h +++ b/src/network/MessageSerializer.h @@ -24,6 +24,8 @@ namespace UNO::NETWORK { static nlohmann::json serializeCards(Iterator begin, Iterator end); static nlohmann::json serializeDiscardPile(const GAME::DiscardPile &discardPile); + static nlohmann::json serializePlayerPublicState(const PlayerPublicState &state); + static nlohmann::json serializePlayerPublicStates(const std::vector &states); static nlohmann::json serializePayload(const std::monostate &payload); static nlohmann::json serializePayload(const JoinGamePayload &payload); @@ -43,6 +45,8 @@ namespace UNO::NETWORK { static GAME::Card deserializeCard(const nlohmann::json &card); static GAME::DiscardPile deserializeDiscardPile(const nlohmann::json &discardPile); static std::multiset deserializeHandCard(const nlohmann::json &handCard); + static PlayerPublicState deserializePlayerPublicState(const nlohmann::json &payload); + static std::vector deserializePlayerPublicStates(const nlohmann::json &payload); static std::monostate deserializeEmptyPayload(const nlohmann::json &payload); static JoinGamePayload deserializeJoinGamePayload(const nlohmann::json &payload); @@ -58,4 +62,4 @@ namespace UNO::NETWORK { static Message deserializeMessage(const nlohmann::json &message); }; -} // namespace UNO::NETWORK \ No newline at end of file +} // namespace UNO::NETWORK diff --git a/src/server/UnoServer.cpp b/src/server/UnoServer.cpp index c584f6b..ff73048 100644 --- a/src/server/UnoServer.cpp +++ b/src/server/UnoServer.cpp @@ -61,8 +61,15 @@ namespace UNO::SERVER { void UnoServer::handleStartGame() { serverGameState_.init(); + std::vector players; + players.reserve(serverGameState_.getPlayers().size()); + for (const auto &player : serverGameState_.getPlayers()) { + players.push_back({player.getName(), player.getRemainingCardCount(), player.getIsUno()}); + } + size_t currentPlayerIndex = static_cast(serverGameState_.getCurrentPlayer() - serverGameState_.getPlayers().begin()); for (size_t i = 0; i < playerCount; i++) { - NETWORK::InitGamePayload payload = {i, serverGameState_.getDiscardPile(), serverGameState_.getPlayers()[i].getCards(), 0}; + NETWORK::InitGamePayload payload = { + i, players, serverGameState_.getDiscardPile(), serverGameState_.getPlayers()[i].getCards(), currentPlayerIndex}; this->networkServer_.send( gameIdToNetworkId.at(i), NETWORK::MessageSerializer::serialize({NETWORK::MessageStatus::OK, NETWORK::MessagePayloadType::INIT_GAME, payload})); @@ -132,4 +139,4 @@ namespace UNO::SERVER { this->networkServer_.run(); } -} // namespace UNO::SERVER \ No newline at end of file +} // namespace UNO::SERVER