From 36e7f533bcad13953e56217c84c569a8f26f60f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Mon, 24 Aug 2026 09:07:11 +0200 Subject: [PATCH] [Client] Add tournament event plumbing and player extension points Wires the client game layer for tournament state without touching existing behavior: - GameEventHandler dispatches Event_TournamentState (2027) to a new tournamentStateChanged signal - GameMetaInfo exposes isTournament and parentGameId over the new ServerInfo_Game field - PlayerEventHandler::processGameEvent is virtual and player is protected; PlayerLogic gains a protected constructor accepting a custom handler, so mode-specific subclasses can intercept events --- .../libcockatrice/game/game_event_handler.cpp | 10 ++++++++ .../libcockatrice/game/game_event_handler.h | 2 ++ .../libcockatrice/game/game_meta_info.h | 21 ++++++++++++++++ .../game/player/player_event_handler.h | 10 ++++---- .../game/player/player_logic.cpp | 13 ++++++++++ .../libcockatrice/game/player/player_logic.h | 25 ++++++++++++++++++- 6 files changed, 75 insertions(+), 6 deletions(-) diff --git a/libcockatrice_game/libcockatrice/game/game_event_handler.cpp b/libcockatrice_game/libcockatrice/game/game_event_handler.cpp index 856475dfa..27526a361 100644 --- a/libcockatrice_game/libcockatrice/game/game_event_handler.cpp +++ b/libcockatrice_game/libcockatrice/game/game_event_handler.cpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -189,6 +190,9 @@ void GameEventHandler::processGameEventContainer(const GameEventContainer &cont, case GameEvent::REVERSE_TURN: eventReverseTurn(event.GetExtension(Event_ReverseTurn::ext), playerId, context); break; + case GameEvent::TOURNAMENT_STATE: + emit tournamentStateChanged(event.GetExtension(Event_TournamentState::ext)); + break; default: { PlayerLogic *player = game->getPlayerManager()->getPlayers().value(playerId, 0); @@ -375,6 +379,12 @@ void GameEventHandler::eventGameStateChanged(const Event_GameStateChanged &event int /*eventPlayerId*/, const GameEventContext & /*context*/) { + // Sub-games of a tournament report their parent hub game so the client can + // route "close game" back to the parent tab. + if (event.parent_game_id() != -1) { + game->getGameMetaInfo()->setParentGameId(event.parent_game_id()); + } + const int playerListSize = event.player_list_size(); QVector>> opponentDecksToDisplay; diff --git a/libcockatrice_game/libcockatrice/game/game_event_handler.h b/libcockatrice_game/libcockatrice/game/game_event_handler.h index f7b11780b..1320d053b 100644 --- a/libcockatrice_game/libcockatrice/game/game_event_handler.h +++ b/libcockatrice_game/libcockatrice/game/game_event_handler.h @@ -50,6 +50,7 @@ class Event_SetActivePhase; class Event_GameSay; class Event_Kicked; class Event_ReverseTurn; +class Event_TournamentState; class Event_Ping; class ServerInfo_PlayerProperties; namespace google @@ -415,6 +416,7 @@ signals: void gameStopped(); void gameClosed(); + void tournamentStateChanged(const Event_TournamentState &state); void playerPropertiesChanged(const ServerInfo_PlayerProperties &prop, int playerId); void playerJoined(const ServerInfo_PlayerProperties &playerInfo); void playerLeft(int leavingPlayerId); diff --git a/libcockatrice_game/libcockatrice/game/game_meta_info.h b/libcockatrice_game/libcockatrice/game/game_meta_info.h index ef8f0c08e..0ea5cd7cc 100644 --- a/libcockatrice_game/libcockatrice/game/game_meta_info.h +++ b/libcockatrice_game/libcockatrice/game/game_meta_info.h @@ -87,6 +87,26 @@ public: return roomGameTypes.find(gameInfo_.game_types(index)).value(); } + bool isTournament() const + { + return gameInfo_.is_tournament(); + } + + void setIsTournament(bool t) + { + gameInfo_.set_is_tournament(t); + } + + int parentGameId() const + { + return parentGameId_; + } + + void setParentGameId(int id) + { + parentGameId_ = id; + } + public slots: void setStarted(bool s) { @@ -111,6 +131,7 @@ signals: private: ServerInfo_Game gameInfo_; + int parentGameId_ = -1; }; #endif // GAME_META_INFO_H diff --git a/libcockatrice_game/libcockatrice/game/player/player_event_handler.h b/libcockatrice_game/libcockatrice/game/player/player_event_handler.h index d253deef0..59e448d7a 100644 --- a/libcockatrice_game/libcockatrice/game/player/player_event_handler.h +++ b/libcockatrice_game/libcockatrice/game/player/player_event_handler.h @@ -93,10 +93,10 @@ public: * @param context Additional context (undo, judge, etc.). * @param options Processing options (UI suppression, reveal behavior). */ - void processGameEvent(GameEvent::GameEventType type, - const GameEvent &event, - const GameEventContext &context, - EventProcessingOptions options); + virtual void processGameEvent(GameEvent::GameEventType type, + const GameEvent &event, + const GameEventContext &context, + EventProcessingOptions options); /** @} */ @@ -277,7 +277,7 @@ signals: */ void cardViewRefreshRequested(CardState *card, bool zoneChanged, PlayerLogic *newOwner); -private: +protected: /** Owning player instance. */ PlayerLogic *player; diff --git a/libcockatrice_game/libcockatrice/game/player/player_logic.cpp b/libcockatrice_game/libcockatrice/game/player/player_logic.cpp index 96bd07164..9098729eb 100644 --- a/libcockatrice_game/libcockatrice/game/player/player_logic.cpp +++ b/libcockatrice_game/libcockatrice/game/player/player_logic.cpp @@ -49,6 +49,19 @@ PlayerLogic::PlayerLogic(const ServerInfo_User &info, initializeZones(); } +PlayerLogic::PlayerLogic(const ServerInfo_User &info, + int _id, + bool _local, + bool _judge, + AbstractGame *_parent, + PlayerEventHandler *customEventHandler) + : QObject(_parent), game(_parent), playerInfo(new PlayerInfo(info, _id, _local, _judge)), + playerEventHandler(customEventHandler), playerActions(new PlayerActions(this)), active(false), conceded(false), + zoneId(0), dialogSemaphore(false) +{ + initializeZones(); +} + void PlayerLogic::initializeZones() { addZone(new PileZoneLogic(this, ZoneNames::DECK, false, true, false, this)); diff --git a/libcockatrice_game/libcockatrice/game/player/player_logic.h b/libcockatrice_game/libcockatrice/game/player/player_logic.h index d6c4f5187..168d5fd5f 100644 --- a/libcockatrice_game/libcockatrice/game/player/player_logic.h +++ b/libcockatrice_game/libcockatrice/game/player/player_logic.h @@ -103,7 +103,30 @@ public: ICardPreferenceProvider *cardPreferences = nullptr); ~PlayerLogic() override; - void initializeZones(); +protected: + /** + * @brief Constructor for subclasses that need a custom event handler (e.g. DraftPlayerLogic). + * + * @p customEventHandler must be non-null and either QObject-parented to this PlayerLogic + * or deleted externally; it is not owned by PlayerLogic. The handler connects to @c player + * during its own constructor, so passing a freshly built subclass handler from an + * initializer list is safe. + */ + PlayerLogic(const ServerInfo_User &info, + int _id, + bool _local, + bool _judge, + AbstractGame *_parent, + PlayerEventHandler *customEventHandler); + +public: + /** + * @brief Creates the standard zone set. + * + * Not virtually dispatched from constructors — subclasses overriding this must add + * their extra zones in their own constructor body. + */ + virtual void initializeZones(); void updateZones(); void clear();