mirror of
https://github.com/kierankihn/uno-game.git
synced 2025-12-27 10:23:16 +08:00
feat(logging): integrate spdlog for enhanced logging and debugging
- Added spdlog dependency to `CMakeLists.txt`. - Implemented a centralized `Logger` with file rotation and console output support. - Added detailed logging across server, client, and game modules for improved traceability.
This commit is contained in:
@@ -8,6 +8,7 @@ find_package(nlohmann_json REQUIRED)
|
|||||||
find_package(asio REQUIRED)
|
find_package(asio REQUIRED)
|
||||||
find_package(argparse REQUIRED)
|
find_package(argparse REQUIRED)
|
||||||
find_package(Slint REQUIRED)
|
find_package(Slint REQUIRED)
|
||||||
|
find_package(spdlog REQUIRED)
|
||||||
|
|
||||||
# Uno Game Library
|
# Uno Game Library
|
||||||
add_library(uno-game-lib
|
add_library(uno-game-lib
|
||||||
@@ -15,6 +16,7 @@ add_library(uno-game-lib
|
|||||||
src/game/CardTile.cpp
|
src/game/CardTile.cpp
|
||||||
src/game/Player.cpp
|
src/game/Player.cpp
|
||||||
src/game/GameState.cpp
|
src/game/GameState.cpp
|
||||||
|
src/common/Logger.cpp
|
||||||
src/common/Utils.cpp
|
src/common/Utils.cpp
|
||||||
src/network/Message.cpp
|
src/network/Message.cpp
|
||||||
src/network/MessageSerializer.cpp
|
src/network/MessageSerializer.cpp
|
||||||
@@ -25,7 +27,8 @@ add_library(uno-game-lib
|
|||||||
target_link_libraries(uno-game-lib PUBLIC nlohmann_json::nlohmann_json)
|
target_link_libraries(uno-game-lib PUBLIC nlohmann_json::nlohmann_json)
|
||||||
target_link_libraries(uno-game-lib PUBLIC asio::asio)
|
target_link_libraries(uno-game-lib PUBLIC asio::asio)
|
||||||
target_link_libraries(uno-game-lib PUBLIC Slint::Slint)
|
target_link_libraries(uno-game-lib PUBLIC Slint::Slint)
|
||||||
target_link_libraries(uno-game-lib PRIVATE argparse::argparse)
|
target_link_libraries(uno-game-lib PUBLIC argparse::argparse)
|
||||||
|
target_link_libraries(uno-game-lib PUBLIC spdlog::spdlog)
|
||||||
|
|
||||||
slint_target_sources(uno-game-lib ui/MainWindow.slint)
|
slint_target_sources(uno-game-lib ui/MainWindow.slint)
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,13 @@
|
|||||||
#include "../network/MessageSerializer.h"
|
#include "../network/MessageSerializer.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace UNO::CLIENT {
|
namespace UNO::CLIENT {
|
||||||
void UnoClient::handleNetworkConnected()
|
void UnoClient::handleNetworkConnected()
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("Connected to server, sending JOIN_GAME message");
|
||||||
NETWORK::JoinGamePayload messagePayload = {this->clientGameState_->getPlayerName()};
|
NETWORK::JoinGamePayload messagePayload = {this->clientGameState_->getPlayerName()};
|
||||||
NETWORK::Message message = {NETWORK::MessageStatus::OK, NETWORK::MessagePayloadType::JOIN_GAME, messagePayload};
|
NETWORK::Message message = {NETWORK::MessageStatus::OK, NETWORK::MessagePayloadType::JOIN_GAME, messagePayload};
|
||||||
networkClient_->send(NETWORK::MessageSerializer::serialize(message));
|
networkClient_->send(NETWORK::MessageSerializer::serialize(message));
|
||||||
@@ -25,11 +27,14 @@ namespace UNO::CLIENT {
|
|||||||
|
|
||||||
void UnoClient::handleNetworkInitGame(const NETWORK::InitGamePayload &payload)
|
void UnoClient::handleNetworkInitGame(const NETWORK::InitGamePayload &payload)
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("Initializing game: player ID={}, {} players total", payload.playerId, payload.players.size());
|
||||||
this->clientGameState_->init(payload.players, payload.discardPile, payload.handCard, payload.currentPlayerIndex, payload.playerId);
|
this->clientGameState_->init(payload.players, payload.discardPile, payload.handCard, payload.currentPlayerIndex, payload.playerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnoClient::handleNetworkPlayCard(const NETWORK::PlayCardPayload &payload)
|
void UnoClient::handleNetworkPlayCard(const NETWORK::PlayCardPayload &payload)
|
||||||
{
|
{
|
||||||
|
SPDLOG_DEBUG(
|
||||||
|
"Received PLAY_CARD: color={}, type={}", static_cast<int>(payload.card.getColor()), static_cast<int>(payload.card.getType()));
|
||||||
if (clientGameState_->getClientGameStage() == GAME::ClientGameStage::ACTIVE) {
|
if (clientGameState_->getClientGameStage() == GAME::ClientGameStage::ACTIVE) {
|
||||||
clientGameState_->play(payload.card);
|
clientGameState_->play(payload.card);
|
||||||
}
|
}
|
||||||
@@ -38,6 +43,7 @@ namespace UNO::CLIENT {
|
|||||||
|
|
||||||
void UnoClient::handleNetworkDrawCard(const NETWORK::DrawCardPayload &payload)
|
void UnoClient::handleNetworkDrawCard(const NETWORK::DrawCardPayload &payload)
|
||||||
{
|
{
|
||||||
|
SPDLOG_DEBUG("Received DRAW_CARD: {} card(s)", payload.drawCount);
|
||||||
if (clientGameState_->getClientGameStage() == GAME::ClientGameStage::ACTIVE) {
|
if (clientGameState_->getClientGameStage() == GAME::ClientGameStage::ACTIVE) {
|
||||||
clientGameState_->draw(payload.cards);
|
clientGameState_->draw(payload.cards);
|
||||||
}
|
}
|
||||||
@@ -46,12 +52,15 @@ namespace UNO::CLIENT {
|
|||||||
|
|
||||||
void UnoClient::handleNetworkEndGame(const NETWORK::EndGamePayload &payload)
|
void UnoClient::handleNetworkEndGame(const NETWORK::EndGamePayload &payload)
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("Game ended");
|
||||||
this->clientGameState_->endGame();
|
this->clientGameState_->endGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnoClient::handleNetworkMessage(const std::string &message)
|
void UnoClient::handleNetworkMessage(const std::string &message)
|
||||||
{
|
{
|
||||||
auto networkMessage = NETWORK::MessageSerializer::deserialize(message);
|
auto networkMessage = NETWORK::MessageSerializer::deserialize(message);
|
||||||
|
SPDLOG_DEBUG("Received network message, type: {}", static_cast<int>(networkMessage.getMessagePayloadType()));
|
||||||
|
|
||||||
if (networkMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::INIT_GAME) {
|
if (networkMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::INIT_GAME) {
|
||||||
this->handleNetworkInitGame(std::get<NETWORK::InitGamePayload>(networkMessage.getMessagePayload()));
|
this->handleNetworkInitGame(std::get<NETWORK::InitGamePayload>(networkMessage.getMessagePayload()));
|
||||||
}
|
}
|
||||||
@@ -68,6 +77,7 @@ namespace UNO::CLIENT {
|
|||||||
if (networkMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::EMPTY
|
if (networkMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::EMPTY
|
||||||
|| networkMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::JOIN_GAME
|
|| networkMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::JOIN_GAME
|
||||||
|| networkMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::START_GAME) {
|
|| networkMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::START_GAME) {
|
||||||
|
SPDLOG_ERROR("Invalid message type from server: {}", static_cast<int>(networkMessage.getMessagePayloadType()));
|
||||||
throw std::invalid_argument("Invalid message type from server");
|
throw std::invalid_argument("Invalid message type from server");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +86,7 @@ namespace UNO::CLIENT {
|
|||||||
|
|
||||||
void UnoClient::handlePlayerAction(PlayerAction action)
|
void UnoClient::handlePlayerAction(PlayerAction action)
|
||||||
{
|
{
|
||||||
|
SPDLOG_DEBUG("Handling player action, type: {}", static_cast<int>(action.playerActionType));
|
||||||
if (action.playerActionType == PlayerActionType::CONNECT) {
|
if (action.playerActionType == PlayerActionType::CONNECT) {
|
||||||
this->handlePlayerConnect(std::get<PlayerConnectPayload>(action.payload));
|
this->handlePlayerConnect(std::get<PlayerConnectPayload>(action.payload));
|
||||||
}
|
}
|
||||||
@@ -93,6 +104,7 @@ namespace UNO::CLIENT {
|
|||||||
|
|
||||||
void UnoClient::handlePlayerConnect(const PlayerConnectPayload &payload)
|
void UnoClient::handlePlayerConnect(const PlayerConnectPayload &payload)
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("Player '{}' connecting to {}:{}", payload.playerName, payload.host, payload.port);
|
||||||
clientGameState_->setPlayerName(payload.playerName);
|
clientGameState_->setPlayerName(payload.playerName);
|
||||||
networkClient_->connect(payload.host, payload.port);
|
networkClient_->connect(payload.host, payload.port);
|
||||||
}
|
}
|
||||||
@@ -100,6 +112,7 @@ namespace UNO::CLIENT {
|
|||||||
|
|
||||||
void UnoClient::handlePlayerStartGame(PlayerStartGamePayload payload)
|
void UnoClient::handlePlayerStartGame(PlayerStartGamePayload payload)
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("Player requests to start game");
|
||||||
NETWORK::StartGamePayload messagePayload = {};
|
NETWORK::StartGamePayload messagePayload = {};
|
||||||
NETWORK::Message message = {NETWORK::MessageStatus::OK, NETWORK::MessagePayloadType::START_GAME, messagePayload};
|
NETWORK::Message message = {NETWORK::MessageStatus::OK, NETWORK::MessagePayloadType::START_GAME, messagePayload};
|
||||||
networkClient_->send(NETWORK::MessageSerializer::serialize(message));
|
networkClient_->send(NETWORK::MessageSerializer::serialize(message));
|
||||||
@@ -115,9 +128,12 @@ namespace UNO::CLIENT {
|
|||||||
|
|
||||||
if ((card->getType() == GAME::CardType::WILD || card->getType() == GAME::CardType::WILDDRAWFOUR)
|
if ((card->getType() == GAME::CardType::WILD || card->getType() == GAME::CardType::WILDDRAWFOUR)
|
||||||
&& card->getColor() != GAME::CardColor::RED) {
|
&& card->getColor() != GAME::CardColor::RED) {
|
||||||
|
SPDLOG_ERROR("Invalid wild card played by player: card doesn't have color set");
|
||||||
throw std::invalid_argument("Invalid card played by player");
|
throw std::invalid_argument("Invalid card played by player");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SPDLOG_INFO("Player plays card: color={}, type={}", card->colorToString(), card->typeToString());
|
||||||
|
|
||||||
NETWORK::PlayCardPayload messagePayload = {
|
NETWORK::PlayCardPayload messagePayload = {
|
||||||
{(card->getType() != GAME::CardType::WILD && card->getType() != GAME::CardType::WILDDRAWFOUR) ? card->getColor()
|
{(card->getType() != GAME::CardType::WILD && card->getType() != GAME::CardType::WILDDRAWFOUR) ? card->getColor()
|
||||||
: payload.color,
|
: payload.color,
|
||||||
@@ -128,6 +144,7 @@ namespace UNO::CLIENT {
|
|||||||
|
|
||||||
void UnoClient::handlePlayerDrawCard(PlayerDrawCardPayload payload)
|
void UnoClient::handlePlayerDrawCard(PlayerDrawCardPayload payload)
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("Player requests to draw card");
|
||||||
NETWORK::DrawCardPayload messagePayload = {};
|
NETWORK::DrawCardPayload messagePayload = {};
|
||||||
NETWORK::Message message = {NETWORK::MessageStatus::OK, NETWORK::MessagePayloadType::DRAW_CARD, messagePayload};
|
NETWORK::Message message = {NETWORK::MessageStatus::OK, NETWORK::MessagePayloadType::DRAW_CARD, messagePayload};
|
||||||
networkClient_->send(NETWORK::MessageSerializer::serialize(message));
|
networkClient_->send(NETWORK::MessageSerializer::serialize(message));
|
||||||
@@ -135,6 +152,7 @@ namespace UNO::CLIENT {
|
|||||||
|
|
||||||
UnoClient::UnoClient()
|
UnoClient::UnoClient()
|
||||||
{
|
{
|
||||||
|
SPDLOG_DEBUG("UnoClient initialized");
|
||||||
clientGameState_ = std::make_shared<GAME::ClientGameState>();
|
clientGameState_ = std::make_shared<GAME::ClientGameState>();
|
||||||
networkClient_ = std::make_shared<NETWORK::NetworkClient>(
|
networkClient_ = std::make_shared<NETWORK::NetworkClient>(
|
||||||
[this]() { this->handleNetworkConnected(); }, [this](const std::string &message) { this->handleNetworkMessage(message); });
|
[this]() { this->handleNetworkConnected(); }, [this](const std::string &message) { this->handleNetworkMessage(message); });
|
||||||
@@ -143,6 +161,7 @@ namespace UNO::CLIENT {
|
|||||||
|
|
||||||
UnoClient::~UnoClient()
|
UnoClient::~UnoClient()
|
||||||
{
|
{
|
||||||
|
SPDLOG_DEBUG("UnoClient shutting down");
|
||||||
networkClient_->stop();
|
networkClient_->stop();
|
||||||
if (networkThread_.joinable()) {
|
if (networkThread_.joinable()) {
|
||||||
networkThread_.join();
|
networkThread_.join();
|
||||||
@@ -151,6 +170,7 @@ namespace UNO::CLIENT {
|
|||||||
|
|
||||||
void UnoClient::run()
|
void UnoClient::run()
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("UnoClient starting");
|
||||||
networkThread_ = std::thread([this]() { this->networkClient_->run(); });
|
networkThread_ = std::thread([this]() { this->networkClient_->run(); });
|
||||||
gameUI_->run();
|
gameUI_->run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
#include "UnoClient.h"
|
#include "UnoClient.h"
|
||||||
|
|
||||||
|
#include "../common/Logger.h"
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
UNO::COMMON::Logger::init("uno-client");
|
||||||
|
SPDLOG_INFO("Starting uno-client application");
|
||||||
|
|
||||||
UNO::CLIENT::UnoClient client;
|
UNO::CLIENT::UnoClient client;
|
||||||
client.run();
|
client.run();
|
||||||
|
|
||||||
|
SPDLOG_INFO("uno-client exited");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
42
src/common/Logger.cpp
Normal file
42
src/common/Logger.cpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* @file Logger.cpp
|
||||||
|
*/
|
||||||
|
#include "Logger.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <spdlog/sinks/rotating_file_sink.h>
|
||||||
|
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
namespace UNO::COMMON {
|
||||||
|
void Logger::init(const std::string &app_name, const std::string &log_dir)
|
||||||
|
{
|
||||||
|
fs::path dir{log_dir};
|
||||||
|
if (!fs::exists(dir)) {
|
||||||
|
fs::create_directories(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto logfile = (dir / (app_name + ".log")).string();
|
||||||
|
|
||||||
|
constexpr std::size_t max_file_size = 5 * 1024 * 1024;
|
||||||
|
constexpr std::size_t max_files = 3;
|
||||||
|
|
||||||
|
auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(logfile, max_file_size, max_files);
|
||||||
|
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
|
||||||
|
|
||||||
|
rotating_sink->set_level(spdlog::level::debug);
|
||||||
|
console_sink->set_level(spdlog::level::info);
|
||||||
|
|
||||||
|
std::vector<spdlog::sink_ptr> sinks{rotating_sink, console_sink};
|
||||||
|
auto logger = std::make_shared<spdlog::logger>(app_name, sinks.begin(), sinks.end());
|
||||||
|
|
||||||
|
logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] [%s:%#] [%!] %v");
|
||||||
|
|
||||||
|
spdlog::register_logger(logger);
|
||||||
|
spdlog::set_default_logger(logger);
|
||||||
|
}
|
||||||
|
} // namespace UNO::COMMON
|
||||||
14
src/common/Logger.h
Normal file
14
src/common/Logger.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* @file Logger.h
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace UNO::COMMON {
|
||||||
|
struct Logger {
|
||||||
|
// Initialize global logging. Safe to call multiple times.
|
||||||
|
// Default log directory aligns with CMake runtime output: <build>/bin/log
|
||||||
|
static void init(const std::string &app_name, const std::string &log_dir = "log");
|
||||||
|
};
|
||||||
|
} // namespace UNO::COMMON
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "GameState.h"
|
#include "GameState.h"
|
||||||
|
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@@ -141,9 +142,11 @@ namespace UNO::GAME {
|
|||||||
this->self_ = this->players_.begin() + static_cast<int>(selfIndex);
|
this->self_ = this->players_.begin() + static_cast<int>(selfIndex);
|
||||||
if (this->self_ == this->currentPlayer_) {
|
if (this->self_ == this->currentPlayer_) {
|
||||||
this->clientGameStage_ = ClientGameStage::ACTIVE;
|
this->clientGameStage_ = ClientGameStage::ACTIVE;
|
||||||
|
SPDLOG_INFO("Client game initialized: {} players, self index: {}, it's our turn", players.size(), selfIndex);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this->clientGameStage_ = ClientGameStage::IDLE;
|
this->clientGameStage_ = ClientGameStage::IDLE;
|
||||||
|
SPDLOG_INFO("Client game initialized: {} players, self index: {}, waiting for turn", players.size(), selfIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,6 +182,7 @@ namespace UNO::GAME {
|
|||||||
|
|
||||||
void ClientGameState::endGame()
|
void ClientGameState::endGame()
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("Client game ended");
|
||||||
this->clientGameStage_ = ClientGameStage::AFTER_GAME;
|
this->clientGameStage_ = ClientGameStage::AFTER_GAME;
|
||||||
this->player_.clear();
|
this->player_.clear();
|
||||||
}
|
}
|
||||||
@@ -190,19 +194,25 @@ namespace UNO::GAME {
|
|||||||
long long currentPlayerIndex = this->currentPlayer_ - this->players_.begin();
|
long long currentPlayerIndex = this->currentPlayer_ - this->players_.begin();
|
||||||
this->players_.push_back(std::move(playerState));
|
this->players_.push_back(std::move(playerState));
|
||||||
this->currentPlayer_ = this->players_.begin() + currentPlayerIndex;
|
this->currentPlayer_ = this->players_.begin() + currentPlayerIndex;
|
||||||
|
SPDLOG_DEBUG("Player '{}' added to game state, total players: {}", playerState.getName(), this->players_.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerGameState::init()
|
void ServerGameState::init()
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("Initializing server game state");
|
||||||
while (discardPile_.isEmpty() || discardPile_.getFront().getType() > CardType::NUM9) {
|
while (discardPile_.isEmpty() || discardPile_.getFront().getType() > CardType::NUM9) {
|
||||||
discardPile_.add(deck_.draw());
|
discardPile_.add(deck_.draw());
|
||||||
}
|
}
|
||||||
|
SPDLOG_DEBUG("Initial discard pile card: color={}, type={}",
|
||||||
|
discardPile_.getFront().colorToString(),
|
||||||
|
discardPile_.getFront().typeToString());
|
||||||
|
|
||||||
for (size_t i = 0; i < 7; i++) {
|
for (size_t i = 0; i < 7; i++) {
|
||||||
for (auto &player : this->players_) {
|
for (auto &player : this->players_) {
|
||||||
player.draw(1, this->deck_.draw(1));
|
player.draw(1, this->deck_.draw(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SPDLOG_INFO("Dealt 7 cards to each of {} players", this->players_.size());
|
||||||
|
|
||||||
this->serverGameStage_ = ServerGameStage::IN_GAME;
|
this->serverGameStage_ = ServerGameStage::IN_GAME;
|
||||||
}
|
}
|
||||||
@@ -212,6 +222,7 @@ namespace UNO::GAME {
|
|||||||
if (this->drawCount_ == 0) {
|
if (this->drawCount_ == 0) {
|
||||||
this->drawCount_ = 1;
|
this->drawCount_ = 1;
|
||||||
}
|
}
|
||||||
|
SPDLOG_DEBUG("Player '{}' drawing {} card(s)", this->currentPlayer_->getName(), this->drawCount_);
|
||||||
auto cards = deck_.draw(this->drawCount_);
|
auto cards = deck_.draw(this->drawCount_);
|
||||||
this->currentPlayer_->draw(this->drawCount_, cards);
|
this->currentPlayer_->draw(this->drawCount_, cards);
|
||||||
this->drawCount_ = 0;
|
this->drawCount_ = 0;
|
||||||
@@ -226,6 +237,7 @@ namespace UNO::GAME {
|
|||||||
|
|
||||||
void ServerGameState::endGame()
|
void ServerGameState::endGame()
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("Ending server game, returning to pre-game state");
|
||||||
this->serverGameStage_ = ServerGameStage::PRE_GAME;
|
this->serverGameStage_ = ServerGameStage::PRE_GAME;
|
||||||
deck_.clear();
|
deck_.clear();
|
||||||
|
|
||||||
|
|||||||
@@ -9,47 +9,63 @@
|
|||||||
#include <asio/connect.hpp>
|
#include <asio/connect.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace UNO::NETWORK {
|
namespace UNO::NETWORK {
|
||||||
NetworkClient::NetworkClient(std::function<void()> onConnect, std::function<void(std::string)> callback) :
|
NetworkClient::NetworkClient(std::function<void()> onConnect, std::function<void(std::string)> callback) :
|
||||||
onConnected_(std::move(onConnect)), callback_(std::move(callback)), workGuard_(asio::make_work_guard(io_context_))
|
onConnected_(std::move(onConnect)), callback_(std::move(callback)), workGuard_(asio::make_work_guard(io_context_))
|
||||||
{
|
{
|
||||||
|
SPDLOG_DEBUG("NetworkClient initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkClient::connect(const std::string &host, uint16_t port)
|
void NetworkClient::connect(const std::string &host, uint16_t port)
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("Connecting to {}:{}", host, port);
|
||||||
auto socket = std::make_shared<asio::ip::tcp::socket>(io_context_);
|
auto socket = std::make_shared<asio::ip::tcp::socket>(io_context_);
|
||||||
auto resolver = std::make_shared<asio::ip::tcp::resolver>(io_context_);
|
auto resolver = std::make_shared<asio::ip::tcp::resolver>(io_context_);
|
||||||
resolver->async_resolve(host,
|
resolver->async_resolve(
|
||||||
std::to_string(port),
|
host,
|
||||||
[this, resolver, socket](const asio::error_code &ec, const asio::ip::tcp::resolver::results_type &results) {
|
std::to_string(port),
|
||||||
if (!ec) {
|
[this, resolver, socket, host, port](const asio::error_code &ec, const asio::ip::tcp::resolver::results_type &results) {
|
||||||
asio::async_connect(
|
if (!ec) {
|
||||||
*socket, results, [this, socket](const asio::error_code &ec, const asio::ip::tcp::endpoint &) {
|
SPDLOG_DEBUG("Resolved host {}:{}", host, port);
|
||||||
if (!ec) {
|
asio::async_connect(
|
||||||
this->session_ = std::make_shared<Session>(std::move(*socket));
|
*socket, results, [this, socket, host, port](const asio::error_code &ec, const asio::ip::tcp::endpoint &) {
|
||||||
this->session_->start(callback_);
|
if (!ec) {
|
||||||
this->onConnected_();
|
SPDLOG_INFO("Successfully connected to {}:{}", host, port);
|
||||||
}
|
this->session_ = std::make_shared<Session>(std::move(*socket));
|
||||||
});
|
this->session_->start(callback_);
|
||||||
}
|
this->onConnected_();
|
||||||
});
|
}
|
||||||
|
else {
|
||||||
|
SPDLOG_ERROR("Failed to connect to {}:{}: {}", host, port, ec.message());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SPDLOG_ERROR("Failed to resolve host {}:{}: {}", host, port, ec.message());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NetworkClient::send(const std::string &message)
|
void NetworkClient::send(const std::string &message)
|
||||||
{
|
{
|
||||||
|
SPDLOG_DEBUG("Queueing message to send, size: {} bytes", message.size());
|
||||||
asio::post(io_context_, [session = this->session_, message]() { session->send(message); });
|
asio::post(io_context_, [session = this->session_, message]() { session->send(message); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkClient::run()
|
void NetworkClient::run()
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("NetworkClient starting io_context loop");
|
||||||
this->io_context_.run();
|
this->io_context_.run();
|
||||||
|
SPDLOG_INFO("NetworkClient io_context loop stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkClient::stop()
|
void NetworkClient::stop()
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("NetworkClient stopping");
|
||||||
this->workGuard_.reset();
|
this->workGuard_.reset();
|
||||||
this->io_context_.stop();
|
this->io_context_.stop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "NetworkServer.h"
|
#include "NetworkServer.h"
|
||||||
|
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace UNO::NETWORK {
|
namespace UNO::NETWORK {
|
||||||
@@ -13,15 +14,20 @@ namespace UNO::NETWORK {
|
|||||||
{
|
{
|
||||||
this->acceptor_.async_accept([this](const asio::error_code &ec, asio::ip::tcp::socket socket) {
|
this->acceptor_.async_accept([this](const asio::error_code &ec, asio::ip::tcp::socket socket) {
|
||||||
if (!ec) {
|
if (!ec) {
|
||||||
|
SPDLOG_INFO("Accepted new connection from {}", socket.remote_endpoint().address().to_string());
|
||||||
this->addPlayer(std::move(socket));
|
this->addPlayer(std::move(socket));
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
SPDLOG_ERROR("Accept error: {}", ec.message());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkServer::NetworkServer(uint16_t port, std::function<void(size_t, std::string)> callback) :
|
NetworkServer::NetworkServer(uint16_t port, std::function<void(size_t, std::string)> callback) :
|
||||||
acceptor_(io_context_, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)), playerCount(0), callback_(std::move(callback))
|
acceptor_(io_context_, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)), playerCount(0), callback_(std::move(callback))
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("NetworkServer initialized on port {}", port);
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,24 +38,30 @@ namespace UNO::NETWORK {
|
|||||||
this->sessions_[playerId] = std::make_shared<Session>(std::move(socket));
|
this->sessions_[playerId] = std::make_shared<Session>(std::move(socket));
|
||||||
this->sessions_[playerId]->start([this, playerId](std::string message) { this->callback_(playerId, std::move(message)); });
|
this->sessions_[playerId]->start([this, playerId](std::string message) { this->callback_(playerId, std::move(message)); });
|
||||||
this->playerCount++;
|
this->playerCount++;
|
||||||
|
SPDLOG_INFO("Player {} added, total players: {}", playerId, this->playerCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkServer::send(size_t id, const std::string &message)
|
void NetworkServer::send(size_t id, const std::string &message)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(this->mutex_);
|
std::lock_guard<std::mutex> lock(this->mutex_);
|
||||||
if (this->sessions_.contains(id) == false) {
|
if (this->sessions_.contains(id) == false) {
|
||||||
|
SPDLOG_ERROR("Failed to send message: Player session {} not found", id);
|
||||||
throw std::invalid_argument("Player session not found");
|
throw std::invalid_argument("Player session not found");
|
||||||
}
|
}
|
||||||
|
SPDLOG_DEBUG("Sending message to player {}, size: {} bytes", id, message.size());
|
||||||
this->sessions_[id]->send(message);
|
this->sessions_[id]->send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkServer::run()
|
void NetworkServer::run()
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("NetworkServer starting io_context loop");
|
||||||
this->io_context_.run();
|
this->io_context_.run();
|
||||||
|
SPDLOG_INFO("NetworkServer io_context loop stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkServer::stop()
|
void NetworkServer::stop()
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("NetworkServer stopping");
|
||||||
this->acceptor_.close();
|
this->acceptor_.close();
|
||||||
this->io_context_.stop();
|
this->io_context_.stop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,17 @@
|
|||||||
*/
|
*/
|
||||||
#include "Session.h"
|
#include "Session.h"
|
||||||
|
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
namespace UNO::NETWORK {
|
namespace UNO::NETWORK {
|
||||||
Session::Session(asio::ip::tcp::socket socket) : socket_(std::move(socket)) {}
|
Session::Session(asio::ip::tcp::socket socket) : socket_(std::move(socket))
|
||||||
|
{
|
||||||
|
SPDLOG_DEBUG("Session created");
|
||||||
|
}
|
||||||
|
|
||||||
void Session::start(std::function<void(std::string)> callback)
|
void Session::start(std::function<void(std::string)> callback)
|
||||||
{
|
{
|
||||||
|
SPDLOG_DEBUG("Session started");
|
||||||
this->callback_ = std::move(callback);
|
this->callback_ = std::move(callback);
|
||||||
this->doRead();
|
this->doRead();
|
||||||
}
|
}
|
||||||
@@ -19,6 +25,7 @@ namespace UNO::NETWORK {
|
|||||||
{
|
{
|
||||||
bool writeInProgress = !this->messages_.empty();
|
bool writeInProgress = !this->messages_.empty();
|
||||||
messages_.push(message);
|
messages_.push(message);
|
||||||
|
SPDLOG_DEBUG("Message queued for sending, size: {} bytes, queue size: {}", message.size(), messages_.size());
|
||||||
if (writeInProgress == false) {
|
if (writeInProgress == false) {
|
||||||
this->doWrite();
|
this->doWrite();
|
||||||
}
|
}
|
||||||
@@ -31,13 +38,18 @@ namespace UNO::NETWORK {
|
|||||||
asio::buffer(messageLength.get(), sizeof(size_t)),
|
asio::buffer(messageLength.get(), sizeof(size_t)),
|
||||||
[this, self = shared_from_this(), messageLength](const asio::error_code &ec, size_t length) {
|
[this, self = shared_from_this(), messageLength](const asio::error_code &ec, size_t length) {
|
||||||
if (!ec) {
|
if (!ec) {
|
||||||
|
SPDLOG_TRACE("Read message header, length: {} bytes", *messageLength);
|
||||||
if (*messageLength <= 10 * 1024 * 1024) {
|
if (*messageLength <= 10 * 1024 * 1024) {
|
||||||
this->doReadBody(*messageLength);
|
this->doReadBody(*messageLength);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
SPDLOG_WARN("Message length {} exceeds limit, skipping", *messageLength);
|
||||||
doRead();
|
doRead();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
SPDLOG_DEBUG("Session read error: {}", ec.message());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,12 +57,16 @@ namespace UNO::NETWORK {
|
|||||||
{
|
{
|
||||||
auto buffer = std::make_shared<std::vector<char>>(length);
|
auto buffer = std::make_shared<std::vector<char>>(length);
|
||||||
asio::async_read(
|
asio::async_read(
|
||||||
socket_, asio::buffer(*buffer), [this, self = shared_from_this(), buffer](const asio::error_code &ec, size_t length) {
|
socket_, asio::buffer(*buffer), [this, self = shared_from_this(), buffer, length](const asio::error_code &ec, size_t) {
|
||||||
if (!ec) {
|
if (!ec) {
|
||||||
std::string message = {buffer->begin(), buffer->end()};
|
std::string message = {buffer->begin(), buffer->end()};
|
||||||
|
SPDLOG_TRACE("Received message body, size: {} bytes", length);
|
||||||
this->callback_(message);
|
this->callback_(message);
|
||||||
doRead();
|
doRead();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
SPDLOG_DEBUG("Session read body error: {}", ec.message());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,10 +78,17 @@ namespace UNO::NETWORK {
|
|||||||
auto length = std::make_shared<size_t>(message.size());
|
auto length = std::make_shared<size_t>(message.size());
|
||||||
auto msg = std::make_shared<std::string>(message);
|
auto msg = std::make_shared<std::string>(message);
|
||||||
|
|
||||||
|
SPDLOG_TRACE("Sending message, size: {} bytes", *length);
|
||||||
std::array<asio::const_buffer, 2> buffers = {asio::buffer(length.get(), sizeof(size_t)), asio::buffer(*msg)};
|
std::array<asio::const_buffer, 2> buffers = {asio::buffer(length.get(), sizeof(size_t)), asio::buffer(*msg)};
|
||||||
asio::async_write(socket_, buffers, [this, self = shared_from_this(), length, msg](const asio::error_code &ec, size_t) {
|
asio::async_write(socket_, buffers, [this, self = shared_from_this(), length, msg](const asio::error_code &ec, size_t) {
|
||||||
if (!ec && this->messages_.empty() == false) {
|
if (!ec) {
|
||||||
this->doWrite();
|
SPDLOG_TRACE("Message sent successfully, size: {} bytes", *length);
|
||||||
|
if (this->messages_.empty() == false) {
|
||||||
|
this->doWrite();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SPDLOG_ERROR("Session write error: {}", ec.message());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,14 @@
|
|||||||
#include "UnoServer.h"
|
#include "UnoServer.h"
|
||||||
|
|
||||||
#include "../network/MessageSerializer.h"
|
#include "../network/MessageSerializer.h"
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
namespace UNO::SERVER {
|
namespace UNO::SERVER {
|
||||||
UnoServer::UnoServer(uint16_t port) :
|
UnoServer::UnoServer(uint16_t port) :
|
||||||
networkServer_(port, [this](size_t playerId, const std::string &message) { this->handlePlayerMessage(playerId, message); }),
|
networkServer_(port, [this](size_t playerId, const std::string &message) { this->handlePlayerMessage(playerId, message); }),
|
||||||
playerCount(0)
|
playerCount(0)
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("UnoServer initialized on port {}", port);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnoServer::handlePlayerMessage(size_t playerId, const std::string &message)
|
void UnoServer::handlePlayerMessage(size_t playerId, const std::string &message)
|
||||||
@@ -20,6 +22,8 @@ namespace UNO::SERVER {
|
|||||||
auto playerMessage = NETWORK::MessageSerializer::deserialize(message);
|
auto playerMessage = NETWORK::MessageSerializer::deserialize(message);
|
||||||
|
|
||||||
if (playerMessage.getMessageStatus() == NETWORK::MessageStatus::OK) {
|
if (playerMessage.getMessageStatus() == NETWORK::MessageStatus::OK) {
|
||||||
|
SPDLOG_DEBUG("Processing message from player {}, type: {}", playerId, static_cast<int>(playerMessage.getMessagePayloadType()));
|
||||||
|
|
||||||
if (playerMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::JOIN_GAME) {
|
if (playerMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::JOIN_GAME) {
|
||||||
auto playerName = std::get<NETWORK::JoinGamePayload>(playerMessage.getMessagePayload()).playerName;
|
auto playerName = std::get<NETWORK::JoinGamePayload>(playerMessage.getMessagePayload()).playerName;
|
||||||
|
|
||||||
@@ -27,12 +31,15 @@ namespace UNO::SERVER {
|
|||||||
this->gameIdToNetworkId[this->playerCount] = playerId;
|
this->gameIdToNetworkId[this->playerCount] = playerId;
|
||||||
this->playerCount++;
|
this->playerCount++;
|
||||||
this->serverGameState_.addPlayer(GAME::ServerPlayerState{playerName, 0, false});
|
this->serverGameState_.addPlayer(GAME::ServerPlayerState{playerName, 0, false});
|
||||||
|
SPDLOG_INFO("Player {} joined with name '{}', game ID: {}", playerId, playerName, this->playerCount - 1);
|
||||||
}
|
}
|
||||||
if (playerMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::START_GAME) {
|
else if (playerMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::START_GAME) {
|
||||||
this->isReadyToStart[networkIdToGameId[playerId]] = true;
|
this->isReadyToStart[networkIdToGameId[playerId]] = true;
|
||||||
|
SPDLOG_INFO("Player {} (game ID: {}) is ready to start", playerId, networkIdToGameId[playerId]);
|
||||||
|
|
||||||
for (size_t i = 0; i <= this->playerCount; i++) {
|
for (size_t i = 0; i <= this->playerCount; i++) {
|
||||||
if (i == this->playerCount) {
|
if (i == this->playerCount) {
|
||||||
|
SPDLOG_INFO("All {} players ready, starting game", this->playerCount);
|
||||||
this->handleStartGame();
|
this->handleStartGame();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -41,25 +48,41 @@ namespace UNO::SERVER {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (playerMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::INIT_GAME
|
else if (playerMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::INIT_GAME
|
||||||
|| playerMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::END_GAME) {
|
|| playerMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::END_GAME) {
|
||||||
|
SPDLOG_ERROR(
|
||||||
|
"Invalid message payload type from client {}: {}", playerId, static_cast<int>(playerMessage.getMessagePayloadType()));
|
||||||
throw std::invalid_argument("Invalid message payload type from client");
|
throw std::invalid_argument("Invalid message payload type from client");
|
||||||
}
|
}
|
||||||
if (this->serverGameState_.getServerGameStage() == GAME::ServerGameStage::IN_GAME
|
else if (this->serverGameState_.getServerGameStage() == GAME::ServerGameStage::IN_GAME
|
||||||
&& this->networkIdToGameId.at(playerId) != this->serverGameState_.getCurrentPlayerId()) {
|
&& this->networkIdToGameId.at(playerId) != this->serverGameState_.getCurrentPlayerId()) {
|
||||||
|
SPDLOG_WARN("Player {} sent message but it's not their turn (current: {})",
|
||||||
|
this->networkIdToGameId.at(playerId),
|
||||||
|
this->serverGameState_.getCurrentPlayerId());
|
||||||
throw std::invalid_argument("Invalid player message: not this player's turn");
|
throw std::invalid_argument("Invalid player message: not this player's turn");
|
||||||
}
|
}
|
||||||
if (playerMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::DRAW_CARD) {
|
else if (playerMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::DRAW_CARD) {
|
||||||
|
SPDLOG_INFO("Player {} (game ID: {}) draws card", playerId, this->networkIdToGameId.at(playerId));
|
||||||
this->handleDrawCard(playerId);
|
this->handleDrawCard(playerId);
|
||||||
}
|
}
|
||||||
if (playerMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::PLAY_CARD) {
|
else if (playerMessage.getMessagePayloadType() == NETWORK::MessagePayloadType::PLAY_CARD) {
|
||||||
this->handlePlayCard(playerId, std::get<NETWORK::PlayCardPayload>(playerMessage.getMessagePayload()).card);
|
auto card = std::get<NETWORK::PlayCardPayload>(playerMessage.getMessagePayload()).card;
|
||||||
|
SPDLOG_INFO("Player {} (game ID: {}) plays card: color={}, type={}",
|
||||||
|
playerId,
|
||||||
|
this->networkIdToGameId.at(playerId),
|
||||||
|
card.colorToString(),
|
||||||
|
card.typeToString());
|
||||||
|
this->handlePlayCard(playerId, card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
SPDLOG_ERROR("Received message with error status from player {}", playerId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnoServer::handleStartGame()
|
void UnoServer::handleStartGame()
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("Initializing game state");
|
||||||
serverGameState_.init();
|
serverGameState_.init();
|
||||||
std::vector<GAME::ClientPlayerState> players;
|
std::vector<GAME::ClientPlayerState> players;
|
||||||
players.reserve(serverGameState_.getPlayers().size());
|
players.reserve(serverGameState_.getPlayers().size());
|
||||||
@@ -67,18 +90,23 @@ namespace UNO::SERVER {
|
|||||||
players.emplace_back(player.getName(), player.getRemainingCardCount(), player.getIsUno());
|
players.emplace_back(player.getName(), player.getRemainingCardCount(), player.getIsUno());
|
||||||
}
|
}
|
||||||
size_t currentPlayerIndex = serverGameState_.getCurrentPlayerId();
|
size_t currentPlayerIndex = serverGameState_.getCurrentPlayerId();
|
||||||
|
SPDLOG_INFO("Game started, current player index: {}", currentPlayerIndex);
|
||||||
|
|
||||||
for (size_t i = 0; i < playerCount; i++) {
|
for (size_t i = 0; i < playerCount; i++) {
|
||||||
NETWORK::InitGamePayload payload = {
|
NETWORK::InitGamePayload payload = {
|
||||||
i, players, serverGameState_.getDiscardPile(), serverGameState_.getPlayers()[i].getCards(), currentPlayerIndex};
|
i, players, serverGameState_.getDiscardPile(), serverGameState_.getPlayers()[i].getCards(), currentPlayerIndex};
|
||||||
this->networkServer_.send(
|
this->networkServer_.send(
|
||||||
gameIdToNetworkId.at(i),
|
gameIdToNetworkId.at(i),
|
||||||
NETWORK::MessageSerializer::serialize({NETWORK::MessageStatus::OK, NETWORK::MessagePayloadType::INIT_GAME, payload}));
|
NETWORK::MessageSerializer::serialize({NETWORK::MessageStatus::OK, NETWORK::MessagePayloadType::INIT_GAME, payload}));
|
||||||
|
SPDLOG_DEBUG("Sent INIT_GAME to player {}", i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnoServer::handleDrawCard(size_t playerId)
|
void UnoServer::handleDrawCard(size_t playerId)
|
||||||
{
|
{
|
||||||
auto cards = this->serverGameState_.updateStateByDraw();
|
auto cards = this->serverGameState_.updateStateByDraw();
|
||||||
|
SPDLOG_INFO("Player {} drew {} card(s)", this->networkIdToGameId.at(playerId), cards.size());
|
||||||
|
|
||||||
for (size_t i = 0; i < playerCount; i++) {
|
for (size_t i = 0; i < playerCount; i++) {
|
||||||
auto networkId = gameIdToNetworkId.at(i);
|
auto networkId = gameIdToNetworkId.at(i);
|
||||||
NETWORK::DrawCardPayload payload;
|
NETWORK::DrawCardPayload payload;
|
||||||
@@ -103,6 +131,7 @@ namespace UNO::SERVER {
|
|||||||
for (const auto &player : this->serverGameState_.getPlayers()) {
|
for (const auto &player : this->serverGameState_.getPlayers()) {
|
||||||
if (player.isEmpty()) {
|
if (player.isEmpty()) {
|
||||||
gameEnded = true;
|
gameEnded = true;
|
||||||
|
SPDLOG_INFO("Player '{}' wins the game!", player.getName());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,6 +149,7 @@ namespace UNO::SERVER {
|
|||||||
|
|
||||||
void UnoServer::handleEndGame()
|
void UnoServer::handleEndGame()
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("Game ended, resetting to pre-game state");
|
||||||
this->serverGameState_.endGame();
|
this->serverGameState_.endGame();
|
||||||
|
|
||||||
NETWORK::EndGamePayload payload{};
|
NETWORK::EndGamePayload payload{};
|
||||||
@@ -136,6 +166,7 @@ namespace UNO::SERVER {
|
|||||||
|
|
||||||
void UnoServer::run()
|
void UnoServer::run()
|
||||||
{
|
{
|
||||||
|
SPDLOG_INFO("UnoServer starting");
|
||||||
this->networkServer_.run();
|
this->networkServer_.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,16 @@
|
|||||||
* @author Yuzhe Guo
|
* @author Yuzhe Guo
|
||||||
* @date 2025.12.01
|
* @date 2025.12.01
|
||||||
*/
|
*/
|
||||||
|
#include "../common/Logger.h"
|
||||||
#include <argparse/argparse.hpp>
|
#include <argparse/argparse.hpp>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
#include "UnoServer.h"
|
#include "UnoServer.h"
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
UNO::COMMON::Logger::init("uno-server");
|
||||||
|
SPDLOG_INFO("Starting uno-server");
|
||||||
|
|
||||||
argparse::ArgumentParser parser("Uno Server", "0.1.0");
|
argparse::ArgumentParser parser("Uno Server", "0.1.0");
|
||||||
|
|
||||||
parser.add_argument("-p", "--port").help("server port").default_value(static_cast<uint16_t>(10001)).scan<'i', uint16_t>();
|
parser.add_argument("-p", "--port").help("server port").default_value(static_cast<uint16_t>(10001)).scan<'i', uint16_t>();
|
||||||
@@ -17,17 +22,18 @@ int main(int argc, char *argv[])
|
|||||||
parser.parse_args(argc, argv);
|
parser.parse_args(argc, argv);
|
||||||
}
|
}
|
||||||
catch (const std::exception &e) {
|
catch (const std::exception &e) {
|
||||||
std::cerr << e.what() << std::endl;
|
SPDLOG_ERROR("Argument parsing failed: {}", e.what());
|
||||||
std::cerr << parser;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
UNO::SERVER::UnoServer uno_server(parser.get<uint16_t>("--port"));
|
auto port = parser.get<uint16_t>("--port");
|
||||||
|
SPDLOG_INFO("Launching server on port {}", port);
|
||||||
|
UNO::SERVER::UnoServer uno_server(port);
|
||||||
uno_server.run();
|
uno_server.run();
|
||||||
}
|
}
|
||||||
catch (const std::exception &e) {
|
catch (const std::exception &e) {
|
||||||
std::cerr << e.what() << std::endl;
|
SPDLOG_ERROR("Server crashed with exception: {}", e.what());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ namespace UNO::UI {
|
|||||||
for (auto color : GAME::AllColors) {
|
for (auto color : GAME::AllColors) {
|
||||||
for (auto type : GAME::AllTypes) {
|
for (auto type : GAME::AllTypes) {
|
||||||
this->images_[{color, type}] =
|
this->images_[{color, type}] =
|
||||||
slint::Image::load_from_path(std::format("../assets/cards/{}.svg", GAME::Card{color, type}.toString()).data());
|
slint::Image::load_from_path(std::format("assets/cards/{}.svg", GAME::Card{color, type}.toString()).data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user