Compare commits

..

14 commits

Author SHA1 Message Date
Lukas Brübach
c1bce86888 [Client] Fix tournament UI includes after the game logic move
The game logic now lives in libcockatrice_game, so the tab's relative
includes into cockatrice/src/game no longer resolve. Include the library
headers instead and pull in the complete types the tab dereferences.
2026-11-03 00:33:11 +01:00
Lukas Brübach
cf76d42791 [Client] Skip decided pairings when resolving live tournament game 2026-11-03 00:29:38 +01:00
Lukas Brübach
c433b165e5 [Tournament] Fold tournament settings hint into the spinbox tooltip
The standalone hint label sat in the form layout's field column with an
empty label cell, which misaligned it against the row above. Per review,
drop the label and carry its text in the spinbox tooltip instead.
2026-11-03 00:29:38 +01:00
Lukas Brübach
a700f8d00d [Client] Address tournament UI review feedback
- Drop the in-game tournament-settings button: Command_TournamentSettingsSelect
  has no server handler (RespContextError), the host-ness decision was evaluated
  once at tab construction, and the button never received a label on first show.
  The dialog can be re-added together with a working Server_Player override.
- Pass PlayerManager::isSpectator() to TournamentWidget instead of relying on
  localPlayerId == -1, which never holds for spectators.
- Report games per match as the total series length (Best of %1) to match the
  DlgTournamentSettings hint and the server's use of the value; the previous
  gamesPerMatch * 2 - 1 mislabeled Bo3 as Best of 5.
- Block signals around read-only tournamentCheckBox setChecked so the disabled
  settings button is not re-enabled, and seed Command_CreateGame through
  mutable_tournament_settings() (field 15 became the settings message).
- return after closing a sub-game that routed to its parent tab.
2026-11-03 00:29:38 +01:00
Lukas Brübach
de983ed01b [Client] Add tournament UI for creating and following lobby tournaments
Wires the tournament protocol into the client:
- DlgCreateGame gains a tournament checkbox with a games-per-match
  settings sub-dialog; both values are sent with Command_CreateGame and
  mirrored in the join-info variant of the dialog
- TournamentWidget renders live standings (with deck-submission state)
  and pairings for the local player's perspective, and asks to open the
  current match game via openMatchGameRequested()
- TournamentTabGameExtension attaches an overview page to TabGame's
  stacked views, mirrors phase and submission progress onto a deck-view
  status strip, and provides round-trip navigation between game view and
  standings; hosts get an in-game settings dialog during deck building
- Open-match falls back to joining as spectator through TabSupervisor;
  sub-games now return to their parent tab on close, falling back to
  the normal leave-game flow when the parent is gone
2026-11-03 00:29:38 +01:00
Lukas Brübach
dfa0edfcdb [Client] Drop dead player event handler extension points
The second PlayerLogic constructor taking a custom PlayerEventHandler was UB
(converting this to PlayerLogic* in the base initializer, and connecting a
freshly-built handler against a not-yet-constructed object), and its abstract
extension surface — virtual initializeZones, virtual getPlayerEventHandler,
virtual processGameEvent, protected player member — has no subclass consumer in
the stack. Revert to the single primary constructor.

Also:
- Drop the unused GameMetaInfo::setIsTournament setter. Tournament status is
  authoritative from Event_GameJoined's ServerInfo_Game; the redundant
  is_tournament field on Event_GameStateChanged is removed in [Protocol].
- Gate the parent-game routing on has_parent_game_id() instead of comparing the
  proto default, so a future drop of the default keeps working.
2026-11-03 00:25:34 +01:00
Lukas Brübach
36e7f533bc [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
2026-11-03 00:25:34 +01:00
Lukas Brübach
d2c93aee7b [Server] Fix tournament stuck-round and sub-game start paths
Gate the host-only start on the hub object so match sub-games can
start, advance the round when a drop decides the last pairing (and on
late results), settle disconnected pairings instead of stalling, and
decide exhausted series by game wins.
2026-11-03 00:25:20 +01:00
Lukas Brübach
84a8b751d3 [Tournament] Fix GameConfig forward declaration and annotate command handlers
Forward-declare GameConfig as struct to match its definition in
game_config.h; the class/struct mismatch trips -Werror
-Wmismatched-tags on macOS.

Also add the missing /// Server: annotations on the tournament
GameCommandType entries now that the Server_AbstractParticipant
handlers they point at exist in the tree.
2026-11-03 00:25:20 +01:00
Lukas Brübach
1c6af5eaba [Server] Stop mirroring is_tournament on the game-state event
The client learns tournament status from Event_GameJoined's ServerInfo_Game;
mirroring it on every Event_GameStateChanged was dead wire data. The field was
removed from the proto in [Protocol]; drop the now-invalidated setter.
2026-11-03 00:25:20 +01:00
Lukas Brübach
5c25f33ca8 [Server] Replay tournament state to late joiners
The bracket, phase and standings live in Event_TournamentState, which only
flows on mutation. Without a copy a player or spectator joining after round
one would sit on an empty bracket until the next advance, so the current
state is now enqueued as part of the join snapshot.

Extracts Event_TournamentState building into buildStateEvent() so both the
broadcast path and the join path share one source of truth.
2026-11-03 00:25:20 +01:00
Lukas Brübach
f25990ff03 [Server] Adapt tournament engine to the shared settings message
- read games per match from Command_CreateGame.tournament_settings after the
  proto rework replaced the standalone games_per_match field
- use qWarning to match the surrounding file
2026-11-03 00:25:20 +01:00
Lukas Brübach
e44ddc1138 [Server] Harden Swiss tournament engine against drops and stalls
- link match sub-games to the hub through QPointer so a finished match can
  never dereference a torn-down parent game
- a player who leaves the hub is dropped: no longer paired, current
  undecided match awarded to the opponent, absent from the bracket
- refuse to spawn a match game when either participant is disconnected, and
  set disconnectRemovesPlayer on match games so a mid-match disconnect ends
  it instead of leaving a half-present participant
- match winner is a strict majority (gamesPerMatch/2+1); an exhausted
  series with no majority is recorded as a draw so the round always advances
- match games are started without force-start: a missing deck no longer
  kicks the player; the game stays open for deck selection
- buyes are handed to every leftover player, worst-ranked first, at most one
  per player over the tournament
- tournament hubs cannot start on mere 'everyone ready': host force-start is
  required and fewer than two players never starts
- sub-game creator copies the real player user info instead of fabricating
  IsAdmin
2026-11-03 00:25:20 +01:00
Lukas Brübach
fe6d4e9e5f [Server] Implement Swiss tournament engine for lobby games
Adds the server-side tournament mode driven through the strategy and
factory interfaces from #7132:
- Server_Tournament runs greedy Swiss pairing with rematch avoidance,
  byes, ceil(log2(n)) rounds, and best-of-N series via gamesPerMatch;
  match sub-games are spawned through the parent game's
  Server_MatchGameFactory implementation with players auto-joined and
  their submitted decks installed
- Tournament lifecycle strategy gates the hub game start until all
  decks are submitted; match result strategy reports sub-game outcomes
  back to the parent tournament
- Server_Game gains tournament state (isTournament flag, settings,
  parent link), protocol fields in getInfo/game state events, a
  full-lobby bypass for tournament hubs, and disconnectRemovesPlayer
  plumbing for upcoming draft modes
- Match-game creation is deferred to the owning thread's event loop so
  room registration never nests lock orders; shared state is guarded by
  the tournament mutex
2026-11-03 00:25:20 +01:00
2 changed files with 5 additions and 2 deletions

View file

@ -1,6 +1,5 @@
#include "tournament_tab_game_extension.h"
#include "../../../game/game_event_handler.h"
#include "../../widgets/draft/tournament_widget.h"
#include "tab_game.h"
#include "tab_supervisor.h"
@ -10,6 +9,10 @@
#include <QPushButton>
#include <QStackedWidget>
#include <QVBoxLayout>
#include <libcockatrice/game/abstract_game.h>
#include <libcockatrice/game/game_event_handler.h>
#include <libcockatrice/game/game_meta_info.h>
#include <libcockatrice/game/player/player_manager.h>
#include <libcockatrice/protocol/pb/event_tournament_state.pb.h>
TournamentTabGameExtension::TournamentTabGameExtension(TabGame *parent) : QObject(parent), tabGame(parent)

2
vcpkg

@ -1 +1 @@
Subproject commit 9eec002df1cd109f8f104cd966a763daf9751489
Subproject commit 9e593bb18ea69cc5095e012465dcd675a822ed0d