mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-06 05:23:56 -07:00
Merge 90c467f2d5 into 430fc117b4
This commit is contained in:
commit
ac1d03e2ae
17 changed files with 2270 additions and 125 deletions
8
Doxyfile
8
Doxyfile
|
|
@ -349,7 +349,7 @@ OPTIMIZE_OUTPUT_SLICE = NO
|
||||||
#
|
#
|
||||||
# Note see also the list of default file extension mappings.
|
# Note see also the list of default file extension mappings.
|
||||||
|
|
||||||
EXTENSION_MAPPING =
|
EXTENSION_MAPPING = proto=C++
|
||||||
|
|
||||||
# If the MARKDOWN_SUPPORT tag is enabled then Doxygen pre-processes all comments
|
# If the MARKDOWN_SUPPORT tag is enabled then Doxygen pre-processes all comments
|
||||||
# according to the Markdown format, which allows for more readable
|
# according to the Markdown format, which allows for more readable
|
||||||
|
|
@ -1086,7 +1086,8 @@ FILE_PATTERNS = *.cc \
|
||||||
*.h++ \
|
*.h++ \
|
||||||
*.markdown \
|
*.markdown \
|
||||||
*.md \
|
*.md \
|
||||||
*.dox
|
*.dox \
|
||||||
|
*.proto
|
||||||
|
|
||||||
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
||||||
# be searched for input files as well.
|
# be searched for input files as well.
|
||||||
|
|
@ -1103,6 +1104,7 @@ RECURSIVE = YES
|
||||||
|
|
||||||
EXCLUDE = build/ \
|
EXCLUDE = build/ \
|
||||||
cmake/ \
|
cmake/ \
|
||||||
|
cmake-build-debug/ \
|
||||||
doc/doxygen/theme/docs/ \
|
doc/doxygen/theme/docs/ \
|
||||||
doc/doxygen/theme/include/ \
|
doc/doxygen/theme/include/ \
|
||||||
vcpkg/
|
vcpkg/
|
||||||
|
|
@ -1182,7 +1184,7 @@ IMAGE_PATH = doc/doxygen/images
|
||||||
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
|
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
|
||||||
# properly processed by Doxygen.
|
# properly processed by Doxygen.
|
||||||
|
|
||||||
INPUT_FILTER =
|
INPUT_FILTER = "python proto2cpp.py"
|
||||||
|
|
||||||
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
|
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
|
||||||
# basis. Doxygen will compare the file name with each pattern and apply the
|
# basis. Doxygen will compare the file name with each pattern and apply the
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,16 @@
|
||||||
/**
|
/**
|
||||||
* @file game_event_handler.h
|
* @file game_event_handler.h
|
||||||
* @ingroup GameLogic
|
* @ingroup GameLogic
|
||||||
|
* @brief Game-level command sender and event dispatcher.
|
||||||
|
*
|
||||||
|
* GameEventHandler sends commands initiated by the local client to the server
|
||||||
|
* and processes incoming game-wide events. It bridges the networking layer
|
||||||
|
* (protobuf events received via AbstractClient) with the game model and UI
|
||||||
|
* (GameState, PlayerManager, logging, widgets).
|
||||||
|
*
|
||||||
|
* Player-scoped events are forwarded to PlayerEventHandler instances, while
|
||||||
|
* spectator and global game events are handled directly here.
|
||||||
*/
|
*/
|
||||||
//! \todo Document this file.
|
|
||||||
|
|
||||||
#ifndef COCKATRICE_GAME_EVENT_HANDLER_H
|
#ifndef COCKATRICE_GAME_EVENT_HANDLER_H
|
||||||
#define COCKATRICE_GAME_EVENT_HANDLER_H
|
#define COCKATRICE_GAME_EVENT_HANDLER_H
|
||||||
|
|
@ -15,92 +23,310 @@
|
||||||
#include <libcockatrice/protocol/pb/serverinfo_player.pb.h>
|
#include <libcockatrice/protocol/pb/serverinfo_player.pb.h>
|
||||||
|
|
||||||
class AbstractClient;
|
class AbstractClient;
|
||||||
class Response;
|
class AbstractGame;
|
||||||
|
class CommandContainer;
|
||||||
|
class GameCommand;
|
||||||
class GameEventContainer;
|
class GameEventContainer;
|
||||||
class GameEventContext;
|
class GameEventContext;
|
||||||
class GameCommand;
|
class PendingCommand;
|
||||||
class GameState;
|
class PlayerLogic;
|
||||||
class MessageLogWidget;
|
class Response;
|
||||||
class CommandContainer;
|
|
||||||
class Event_GameJoined;
|
|
||||||
class Event_GameStateChanged;
|
class Event_GameStateChanged;
|
||||||
class Event_PlayerPropertiesChanged;
|
class Event_PlayerPropertiesChanged;
|
||||||
class Event_Join;
|
class Event_Join;
|
||||||
class Event_Leave;
|
class Event_Leave;
|
||||||
class Event_GameHostChanged;
|
class Event_GameHostChanged;
|
||||||
class Event_GameClosed;
|
class Event_GameClosed;
|
||||||
class Event_GameStart;
|
|
||||||
class Event_SetActivePlayer;
|
class Event_SetActivePlayer;
|
||||||
class Event_SetActivePhase;
|
class Event_SetActivePhase;
|
||||||
class Event_Ping;
|
|
||||||
class Event_GameSay;
|
class Event_GameSay;
|
||||||
class Event_Kicked;
|
class Event_Kicked;
|
||||||
class Event_ReverseTurn;
|
class Event_ReverseTurn;
|
||||||
class AbstractGame;
|
class Event_Ping;
|
||||||
class PendingCommand;
|
|
||||||
class PlayerLogic;
|
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(GameEventHandlerLog, "game_event_handler");
|
inline Q_LOGGING_CATEGORY(GameEventHandlerLog, "game_event_handler");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class GameEventHandler
|
||||||
|
* @brief Central dispatcher for game-wide commands and events.
|
||||||
|
*
|
||||||
|
* This class owns no game state itself. Instead, it:
|
||||||
|
* - Sends commands to the server on behalf of local players
|
||||||
|
* - Receives and dispatches server-side game events
|
||||||
|
* - Updates the game model indirectly via Player, GameState, and PlayerManager
|
||||||
|
* - Emits high-level signals for UI updates and logging
|
||||||
|
*/
|
||||||
class GameEventHandler : public QObject
|
class GameEventHandler : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/** Pointer to the owning game instance. */
|
||||||
AbstractGame *game;
|
AbstractGame *game;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/** @name Construction
|
||||||
|
* Lifecycle and ownership.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a GameEventHandler.
|
||||||
|
*
|
||||||
|
* The handler is owned by the AbstractGame instance and uses it to
|
||||||
|
* access the game state, players, and network clients.
|
||||||
|
*
|
||||||
|
* @param _game Owning game instance (also used as QObject parent).
|
||||||
|
*/
|
||||||
explicit GameEventHandler(AbstractGame *_game);
|
explicit GameEventHandler(AbstractGame *_game);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Outgoing game commands
|
||||||
|
* Commands initiated locally and sent to the server.
|
||||||
|
*
|
||||||
|
* These methods construct and send protobuf commands corresponding
|
||||||
|
* to user actions in the UI.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @brief Request advancing the game to the next turn. */
|
||||||
void handleNextTurn();
|
void handleNextTurn();
|
||||||
|
|
||||||
|
/** @brief Request reversing the current turn order. */
|
||||||
void handleReverseTurn();
|
void handleReverseTurn();
|
||||||
|
|
||||||
|
/** @brief Concede the game for the currently active local player. */
|
||||||
void handleActiveLocalPlayerConceded();
|
void handleActiveLocalPlayerConceded();
|
||||||
|
|
||||||
|
/** @brief Undo a previous concede for the active local player. */
|
||||||
void handleActiveLocalPlayerUnconceded();
|
void handleActiveLocalPlayerUnconceded();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the active phase of the game.
|
||||||
|
*
|
||||||
|
* Typically triggered by the active player selecting a new phase.
|
||||||
|
*
|
||||||
|
* @param phase Phase identifier.
|
||||||
|
*/
|
||||||
void handleActivePhaseChanged(int phase);
|
void handleActivePhaseChanged(int phase);
|
||||||
|
|
||||||
|
/** @brief Leave the current game session. */
|
||||||
void handleGameLeft();
|
void handleGameLeft();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a chat message to all players and spectators.
|
||||||
|
*
|
||||||
|
* @param chatMessage Message text.
|
||||||
|
*/
|
||||||
void handleChatMessageSent(const QString &chatMessage);
|
void handleChatMessageSent(const QString &chatMessage);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete an existing arrow.
|
||||||
|
*
|
||||||
|
* @param arrowId Unique identifier of the arrow to delete.
|
||||||
|
*/
|
||||||
void handleArrowDeletion(int creatorId, int arrowId);
|
void handleArrowDeletion(int creatorId, int arrowId);
|
||||||
void handleArrowDeletionFinished(const Response &response, int creatorId, int arrowId);
|
void handleArrowDeletionFinished(const Response &response, int creatorId, int arrowId);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Incoming event processing
|
||||||
|
* Entry points for server-sent events.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Process a container of game events received from the server.
|
||||||
|
*
|
||||||
|
* This is the main dispatch function for incoming game events.
|
||||||
|
* Events are routed to spectator handlers, game-level handlers,
|
||||||
|
* or forwarded to PlayerEventHandler instances as appropriate.
|
||||||
|
*
|
||||||
|
* @param cont Game event container from the server.
|
||||||
|
* @param client Client that received the container.
|
||||||
|
* @param options Processing flags (e.g. silent, replay).
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
processGameEventContainer(const GameEventContainer &cont, AbstractClient *client, EventProcessingOptions options);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Command preparation helpers
|
||||||
|
* Internal helpers for building command containers.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wrap a single protobuf command in a PendingCommand.
|
||||||
|
*
|
||||||
|
* @param cmd Protobuf command message.
|
||||||
|
* @return Newly allocated PendingCommand (caller takes ownership).
|
||||||
|
*/
|
||||||
|
PendingCommand *prepareGameCommand(const ::google::protobuf::Message &cmd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wrap multiple protobuf commands in a single PendingCommand.
|
||||||
|
*
|
||||||
|
* Ownership of the messages in cmdList is transferred to the handler.
|
||||||
|
*
|
||||||
|
* @param cmdList List of protobuf command messages.
|
||||||
|
* @return Newly allocated PendingCommand.
|
||||||
|
*/
|
||||||
|
PendingCommand *prepareGameCommand(const QList<const ::google::protobuf::Message *> &cmdList);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Spectator event handlers
|
||||||
|
* Events originating from spectators.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle a spectator chat message.
|
||||||
|
*/
|
||||||
void eventSpectatorSay(const Event_GameSay &event, int eventPlayerId, const GameEventContext &context);
|
void eventSpectatorSay(const Event_GameSay &event, int eventPlayerId, const GameEventContext &context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle a spectator leaving the game.
|
||||||
|
*/
|
||||||
void eventSpectatorLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext &context);
|
void eventSpectatorLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext &context);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Game state event handlers
|
||||||
|
* Events that affect global game state.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle a full game state update from the server.
|
||||||
|
*
|
||||||
|
* Used during game startup, reconnection, and resynchronization.
|
||||||
|
*/
|
||||||
void eventGameStateChanged(const Event_GameStateChanged &event, int eventPlayerId, const GameEventContext &context);
|
void eventGameStateChanged(const Event_GameStateChanged &event, int eventPlayerId, const GameEventContext &context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update card attachment relationships for all players.
|
||||||
|
*
|
||||||
|
* Called after a game state update to ensure attachments are resolved
|
||||||
|
* consistently across all zones.
|
||||||
|
*/
|
||||||
void processCardAttachmentsForPlayers(const Event_GameStateChanged &event);
|
void processCardAttachmentsForPlayers(const Event_GameStateChanged &event);
|
||||||
|
|
||||||
|
/** @brief Handle a change in game host. */
|
||||||
|
void eventGameHostChanged(const Event_GameHostChanged &event, int eventPlayerId, const GameEventContext &context);
|
||||||
|
|
||||||
|
/** @brief Handle the game being closed by the server. */
|
||||||
|
void eventGameClosed(const Event_GameClosed &event, int eventPlayerId, const GameEventContext &context);
|
||||||
|
|
||||||
|
/** @brief Handle a change of the active player. */
|
||||||
|
void eventSetActivePlayer(const Event_SetActivePlayer &event, int eventPlayerId, const GameEventContext &context);
|
||||||
|
|
||||||
|
/** @brief Handle a change of the active phase. */
|
||||||
|
void eventSetActivePhase(const Event_SetActivePhase &event, int eventPlayerId, const GameEventContext &context);
|
||||||
|
|
||||||
|
/** @brief Handle a turn reversal event. */
|
||||||
|
void eventReverseTurn(const Event_ReverseTurn &event, int eventPlayerId, const GameEventContext &context);
|
||||||
|
|
||||||
|
/** @brief Handle ping / latency updates. */
|
||||||
|
void eventPing(const Event_Ping &event, int eventPlayerId, const GameEventContext &context);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Player lifecycle and property handlers
|
||||||
|
* Events related to players joining, leaving, or changing state.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle updates to a player's properties.
|
||||||
|
*
|
||||||
|
* Includes readiness, concede state, deck selection, sideboard lock,
|
||||||
|
* and connection state changes.
|
||||||
|
*/
|
||||||
void eventPlayerPropertiesChanged(const Event_PlayerPropertiesChanged &event,
|
void eventPlayerPropertiesChanged(const Event_PlayerPropertiesChanged &event,
|
||||||
int eventPlayerId,
|
int eventPlayerId,
|
||||||
const GameEventContext &context);
|
const GameEventContext &context);
|
||||||
|
|
||||||
|
/** @brief Handle a player or spectator joining the game. */
|
||||||
void eventJoin(const Event_Join &event, int eventPlayerId, const GameEventContext &context);
|
void eventJoin(const Event_Join &event, int eventPlayerId, const GameEventContext &context);
|
||||||
|
|
||||||
|
/** @brief Handle a player leaving the game. */
|
||||||
void eventLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext &context);
|
void eventLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext &context);
|
||||||
QString getLeaveReason(Event_Leave::LeaveReason reason);
|
|
||||||
|
/** @brief Handle the local player being kicked from the game. */
|
||||||
void eventKicked(const Event_Kicked &event, int eventPlayerId, const GameEventContext &context);
|
void eventKicked(const Event_Kicked &event, int eventPlayerId, const GameEventContext &context);
|
||||||
void eventGameHostChanged(const Event_GameHostChanged &event, int eventPlayerId, const GameEventContext &context);
|
|
||||||
void eventGameClosed(const Event_GameClosed &event, int eventPlayerId, const GameEventContext &context);
|
|
||||||
|
|
||||||
void eventSetActivePlayer(const Event_SetActivePlayer &event, int eventPlayerId, const GameEventContext &context);
|
/**
|
||||||
void eventSetActivePhase(const Event_SetActivePhase &event, int eventPlayerId, const GameEventContext &context);
|
* @brief Convert a leave reason enum to a human-readable string.
|
||||||
void eventPing(const Event_Ping &event, int eventPlayerId, const GameEventContext &context);
|
*/
|
||||||
void eventReverseTurn(const Event_ReverseTurn &event, int eventPlayerId, const GameEventContext & /*context*/);
|
QString getLeaveReason(Event_Leave::LeaveReason reason);
|
||||||
|
|
||||||
void commandFinished(const Response &response);
|
/** @} */
|
||||||
|
|
||||||
void
|
|
||||||
processGameEventContainer(const GameEventContainer &cont, AbstractClient *client, EventProcessingOptions options);
|
|
||||||
PendingCommand *prepareGameCommand(const ::google::protobuf::Message &cmd);
|
|
||||||
PendingCommand *prepareGameCommand(const QList<const ::google::protobuf::Message *> &cmdList);
|
|
||||||
public slots:
|
public slots:
|
||||||
|
/** @name Command dispatch slots
|
||||||
|
* Low-level command transmission.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a prepared PendingCommand.
|
||||||
|
*
|
||||||
|
* @param pend Pending command to send.
|
||||||
|
* @param playerId Player whose client should send the command.
|
||||||
|
*/
|
||||||
void sendGameCommand(PendingCommand *pend, int playerId = -1);
|
void sendGameCommand(PendingCommand *pend, int playerId = -1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a single protobuf command.
|
||||||
|
*
|
||||||
|
* @param command Protobuf command message.
|
||||||
|
* @param playerId Player whose client should send the command.
|
||||||
|
*/
|
||||||
void sendGameCommand(const ::google::protobuf::Message &command, int playerId = -1);
|
void sendGameCommand(const ::google::protobuf::Message &command, int playerId = -1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called when a PendingCommand finishes execution.
|
||||||
|
*
|
||||||
|
* Used to detect server-side errors such as chat flood protection.
|
||||||
|
*/
|
||||||
|
void commandFinished(const Response &response);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
/** @name Core state signals
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
void emitUserEvent();
|
void emitUserEvent();
|
||||||
|
void containerProcessingStarted(GameEventContext context);
|
||||||
|
void containerProcessingDone();
|
||||||
|
void gameFlooded();
|
||||||
|
void setContextJudgeName(QString judgeName);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Player and spectator signals
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
void addPlayerToAutoCompleteList(QString playerName);
|
void addPlayerToAutoCompleteList(QString playerName);
|
||||||
void localPlayerDeckSelected(PlayerLogic *localPlayer, int playerId, ServerInfo_Player playerInfo);
|
void localPlayerDeckSelected(PlayerLogic *localPlayer, int playerId, ServerInfo_Player playerInfo);
|
||||||
void remotePlayerDeckSelected(QString deckList, int playerId, QString playerName);
|
void remotePlayerDeckSelected(QString deckList, int playerId, QString playerName);
|
||||||
void remotePlayersDecksSelected(QVector<QPair<int, QPair<QString, QString>>> opponentDecks);
|
void remotePlayersDecksSelected(QVector<QPair<int, QPair<QString, QString>>> opponentDecks);
|
||||||
void localPlayerSideboardLocked(int playerId, bool sideboardLocked);
|
void localPlayerSideboardLocked(int playerId, bool sideboardLocked);
|
||||||
void localPlayerReadyStateChanged(int playerId, bool ready);
|
void localPlayerReadyStateChanged(int playerId, bool ready);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Game flow signals
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
void gameStopped();
|
void gameStopped();
|
||||||
void gameClosed();
|
void gameClosed();
|
||||||
void playerPropertiesChanged(const ServerInfo_PlayerProperties &prop, int playerId);
|
void playerPropertiesChanged(const ServerInfo_PlayerProperties &prop, int playerId);
|
||||||
|
|
@ -109,11 +335,15 @@ signals:
|
||||||
void playerKicked();
|
void playerKicked();
|
||||||
void spectatorJoined(const ServerInfo_PlayerProperties &spectatorInfo);
|
void spectatorJoined(const ServerInfo_PlayerProperties &spectatorInfo);
|
||||||
void spectatorLeft(int leavingSpectatorId);
|
void spectatorLeft(int leavingSpectatorId);
|
||||||
void gameFlooded();
|
|
||||||
void containerProcessingStarted(GameEventContext context);
|
|
||||||
void setContextJudgeName(QString judgeName);
|
|
||||||
void containerProcessingDone();
|
|
||||||
void arrowDeleted(int creatorId, int arrowId);
|
void arrowDeleted(int creatorId, int arrowId);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Logging signals
|
||||||
|
* Signals consumed by MessageLogWidget.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
void logSpectatorSay(ServerInfo_User userInfo, QString message);
|
void logSpectatorSay(ServerInfo_User userInfo, QString message);
|
||||||
void logSpectatorLeave(QString name, QString reason);
|
void logSpectatorLeave(QString name, QString reason);
|
||||||
void logGameStart();
|
void logGameStart();
|
||||||
|
|
@ -132,6 +362,8 @@ signals:
|
||||||
void logActivePhaseChanged(int activePhase);
|
void logActivePhaseChanged(int activePhase);
|
||||||
void logConcede(int playerId);
|
void logConcede(int playerId);
|
||||||
void logUnconcede(int playerId);
|
void logUnconcede(int playerId);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COCKATRICE_GAME_EVENT_HANDLER_H
|
#endif // COCKATRICE_GAME_EVENT_HANDLER_H
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,24 @@
|
||||||
/**
|
/**
|
||||||
* @file player_event_handler.h
|
* @file player_event_handler.h
|
||||||
* @ingroup GameLogicPlayers
|
* @ingroup GameLogicPlayers
|
||||||
|
* @brief Player-scoped game event handler.
|
||||||
|
*
|
||||||
|
* PlayerEventHandler applies game events that affect a single Player’s
|
||||||
|
* board state, zones, cards, counters, arrows, and related UI/log output.
|
||||||
|
*
|
||||||
|
* It is invoked by GameEventHandler after basic routing and validation.
|
||||||
|
* Each instance is bound 1:1 to a Player and must never mutate state
|
||||||
|
* belonging to other players except where explicitly required by events
|
||||||
|
* (e.g. moving cards between players, attaching cards, arrows).
|
||||||
|
*
|
||||||
|
* This class is intentionally stateful and tightly coupled to Player,
|
||||||
|
* PlayerActions, and the board/zones implementation. It performs both
|
||||||
|
* model mutation and UI-side bookkeeping (zone views, arrows, menus).
|
||||||
*/
|
*/
|
||||||
//! \todo Document this file.
|
|
||||||
|
|
||||||
#ifndef COCKATRICE_PLAYER_EVENT_HANDLER_H
|
#ifndef COCKATRICE_PLAYER_EVENT_HANDLER_H
|
||||||
#define COCKATRICE_PLAYER_EVENT_HANDLER_H
|
#define COCKATRICE_PLAYER_EVENT_HANDLER_H
|
||||||
|
|
||||||
#include "event_processing_options.h"
|
#include "event_processing_options.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
@ -16,6 +29,7 @@
|
||||||
class CardItem;
|
class CardItem;
|
||||||
class CardZoneLogic;
|
class CardZoneLogic;
|
||||||
class PlayerLogic;
|
class PlayerLogic;
|
||||||
|
|
||||||
class Event_AttachCard;
|
class Event_AttachCard;
|
||||||
class Event_ChangeZoneProperties;
|
class Event_ChangeZoneProperties;
|
||||||
class Event_CreateArrow;
|
class Event_CreateArrow;
|
||||||
|
|
@ -37,11 +51,176 @@ class Event_SetCounter;
|
||||||
class Event_Shuffle;
|
class Event_Shuffle;
|
||||||
class Event_GameLogNotice;
|
class Event_GameLogNotice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class PlayerEventHandler
|
||||||
|
* @brief Applies player-specific game events and emits corresponding log signals.
|
||||||
|
*
|
||||||
|
* Design notes:
|
||||||
|
* - All event handlers assume events are authoritative and already validated
|
||||||
|
* by the server.
|
||||||
|
* - Most handlers mutate both logical state (CardItem, CardZoneLogic, counters)
|
||||||
|
* and visual/UI state (views, arrows, menus).
|
||||||
|
* - Logging signals are emitted *after* or *during* state mutation, depending
|
||||||
|
* on whether later mutations would invalidate log data.
|
||||||
|
*/
|
||||||
class PlayerEventHandler : public QObject
|
class PlayerEventHandler : public QObject
|
||||||
{
|
{
|
||||||
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a PlayerEventHandler bound to a Player.
|
||||||
|
* @param player Owning player instance.
|
||||||
|
*/
|
||||||
|
explicit PlayerEventHandler(PlayerLogic *player);
|
||||||
|
|
||||||
|
/** @name Event dispatch
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dispatch a generic GameEvent to the appropriate handler.
|
||||||
|
*
|
||||||
|
* This is the single entry point used by GameEventHandler. It extracts
|
||||||
|
* the correct protobuf extension and forwards the event to a typed
|
||||||
|
* handler method.
|
||||||
|
*
|
||||||
|
* @param type Game event type enum.
|
||||||
|
* @param event Generic protobuf container.
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Chat and randomization events
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// Handle in-game chat messages from this player.
|
||||||
|
void eventGameSay(const Event_GameSay &event);
|
||||||
|
|
||||||
|
/// Handle zone shuffle events (typically libraries).
|
||||||
|
void eventShuffle(const Event_Shuffle &event);
|
||||||
|
|
||||||
|
/// Handle die roll events.
|
||||||
|
void eventRollDie(const Event_RollDie &event);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Arrow and targeting events
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// Create a visual arrow between cards or players.
|
||||||
|
void eventCreateArrow(const Event_CreateArrow &event);
|
||||||
|
|
||||||
|
/// Delete an existing arrow.
|
||||||
|
void eventDeleteArrow(const Event_DeleteArrow &event);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Token and card creation
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// Create a token card in a target zone.
|
||||||
|
void eventCreateToken(const Event_CreateToken &event);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Card attribute and counter updates
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set a card attribute (tapped, PT, annotation, etc.).
|
||||||
|
*
|
||||||
|
* May apply to a single card or all cards in a zone if no card ID
|
||||||
|
* is provided by the event.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
eventSetCardAttr(const Event_SetCardAttr &event, const GameEventContext &context, EventProcessingOptions options);
|
||||||
|
|
||||||
|
/// Update a counter attached to a card.
|
||||||
|
void eventSetCardCounter(const Event_SetCardCounter &event);
|
||||||
|
|
||||||
|
/// Create a player-level counter.
|
||||||
|
void eventCreateCounter(const Event_CreateCounter &event);
|
||||||
|
|
||||||
|
/// Set a player-level counter value.
|
||||||
|
void eventSetCounter(const Event_SetCounter &event);
|
||||||
|
|
||||||
|
/// Delete a player-level counter.
|
||||||
|
void eventDelCounter(const Event_DelCounter &event);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Zone-level operations
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// Log a zone dump (e.g. reveal graveyard/library contents).
|
||||||
|
void eventDumpZone(const Event_DumpZone &event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move a card between zones and/or players.
|
||||||
|
*
|
||||||
|
* This is one of the most complex handlers:
|
||||||
|
* - Removes the card from the start zone
|
||||||
|
* - Updates card identity and ownership if needed
|
||||||
|
* - Handles attachments and arrows
|
||||||
|
* - Emits appropriate move or undo-draw logs
|
||||||
|
* - Inserts the card into the target zone
|
||||||
|
*/
|
||||||
|
void eventMoveCard(const Event_MoveCard &event, const GameEventContext &context);
|
||||||
|
|
||||||
|
/// Flip a card face up or face down.
|
||||||
|
void eventFlipCard(const Event_FlipCard &event);
|
||||||
|
|
||||||
|
/// Destroy a card and clean up attachments.
|
||||||
|
void eventDestroyCard(const Event_DestroyCard &event);
|
||||||
|
|
||||||
|
/// Attach or detach a card to/from another card.
|
||||||
|
void eventAttachCard(const Event_AttachCard &event);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Draw and reveal operations
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// Draw one or more cards from the deck.
|
||||||
|
void eventDrawCards(const Event_DrawCards &event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reveal cards from a zone.
|
||||||
|
*
|
||||||
|
* Handles peeking, in-place top-card reveals, full reveal windows,
|
||||||
|
* and write-access granting.
|
||||||
|
*/
|
||||||
|
void eventRevealCards(const Event_RevealCards &event, EventProcessingOptions options);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Zone configuration
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// Update zone visibility and reveal behavior.
|
||||||
|
void eventChangeZoneProperties(const Event_ChangeZoneProperties &event);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
void eventGameLogNotice(const Event_GameLogNotice &event);
|
||||||
signals:
|
signals:
|
||||||
|
/** @name Logging signals
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
void logSay(PlayerLogic *player, QString message);
|
void logSay(PlayerLogic *player, QString message);
|
||||||
void logShuffle(PlayerLogic *player, CardZoneLogic *zone, int start, int end);
|
void logShuffle(PlayerLogic *player, CardZoneLogic *zone, int start, int end);
|
||||||
void logRollDie(PlayerLogic *player, int sides, const QList<uint> &rolls);
|
void logRollDie(PlayerLogic *player, int sides, const QList<uint> &rolls);
|
||||||
|
|
@ -82,40 +261,13 @@ signals:
|
||||||
bool isLentToAnotherPlayer = false);
|
bool isLentToAnotherPlayer = false);
|
||||||
void logAlwaysRevealTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal);
|
void logAlwaysRevealTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal);
|
||||||
void logAlwaysLookAtTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal);
|
void logAlwaysLookAtTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal);
|
||||||
|
/** @} */
|
||||||
|
|
||||||
void cardZoneChanged(CardItem *card, bool sameZone);
|
void cardZoneChanged(CardItem *card, bool sameZone);
|
||||||
void requestCardMenuUpdate(const CardItem *card);
|
void requestCardMenuUpdate(const CardItem *card);
|
||||||
|
|
||||||
public:
|
|
||||||
PlayerEventHandler(PlayerLogic *player);
|
|
||||||
|
|
||||||
void processGameEvent(GameEvent::GameEventType type,
|
|
||||||
const GameEvent &event,
|
|
||||||
const GameEventContext &context,
|
|
||||||
EventProcessingOptions options);
|
|
||||||
|
|
||||||
void eventGameSay(const Event_GameSay &event);
|
|
||||||
void eventShuffle(const Event_Shuffle &event);
|
|
||||||
void eventRollDie(const Event_RollDie &event);
|
|
||||||
void eventCreateArrow(const Event_CreateArrow &event);
|
|
||||||
void eventDeleteArrow(const Event_DeleteArrow &event);
|
|
||||||
void eventCreateToken(const Event_CreateToken &event);
|
|
||||||
void
|
|
||||||
eventSetCardAttr(const Event_SetCardAttr &event, const GameEventContext &context, EventProcessingOptions options);
|
|
||||||
void eventSetCardCounter(const Event_SetCardCounter &event);
|
|
||||||
void eventCreateCounter(const Event_CreateCounter &event);
|
|
||||||
void eventSetCounter(const Event_SetCounter &event);
|
|
||||||
void eventDelCounter(const Event_DelCounter &event);
|
|
||||||
void eventDumpZone(const Event_DumpZone &event);
|
|
||||||
void eventMoveCard(const Event_MoveCard &event, const GameEventContext &context);
|
|
||||||
void eventFlipCard(const Event_FlipCard &event);
|
|
||||||
void eventDestroyCard(const Event_DestroyCard &event);
|
|
||||||
void eventAttachCard(const Event_AttachCard &event);
|
|
||||||
void eventDrawCards(const Event_DrawCards &event);
|
|
||||||
void eventRevealCards(const Event_RevealCards &event, EventProcessingOptions options);
|
|
||||||
void eventChangeZoneProperties(const Event_ChangeZoneProperties &event);
|
|
||||||
void eventGameLogNotice(const Event_GameLogNotice &event);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/** Owning player instance. */
|
||||||
PlayerLogic *player;
|
PlayerLogic *player;
|
||||||
|
|
||||||
void setCardAttrHelper(const GameEventContext &context,
|
void setCardAttrHelper(const GameEventContext &context,
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,6 @@
|
||||||
- @subpage querying_the_card_database
|
- @subpage querying_the_card_database
|
||||||
|
|
||||||
- @subpage loading_card_pictures
|
- @subpage loading_card_pictures
|
||||||
- @subpage displaying_cards
|
- @subpage displaying_cards
|
||||||
|
|
||||||
|
- @subpage developer_reference_network_overview
|
||||||
|
|
@ -0,0 +1,170 @@
|
||||||
|
@page game_event_handler GameEventHandler
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
`GameEventHandler` is the central coordinator for **game-wide commands and events**.
|
||||||
|
It acts as the bridge between the networking layer (protobuf messages received from
|
||||||
|
the server) and the local game model and UI.
|
||||||
|
|
||||||
|
Unlike `PlayerEventHandler`, which is responsible for player-scoped state and zones,
|
||||||
|
`GameEventHandler` handles:
|
||||||
|
|
||||||
|
- Global game flow (turns, phases, host changes)
|
||||||
|
- Player and spectator lifecycle events
|
||||||
|
- Chat and logging events
|
||||||
|
- Dispatching incoming events to the appropriate subsystem
|
||||||
|
- Sending locally initiated commands to the server
|
||||||
|
|
||||||
|
In short, it is the **top-level event dispatcher** for an active game.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Responsibilities
|
||||||
|
|
||||||
|
`GameEventHandler` has four primary responsibilities:
|
||||||
|
|
||||||
|
### 1. Sending game-wide commands
|
||||||
|
|
||||||
|
UI actions that affect the game as a whole (e.g. advancing the turn, changing phases,
|
||||||
|
sending chat messages) are translated into protobuf commands and sent to the server
|
||||||
|
via this class.
|
||||||
|
|
||||||
|
Examples include:
|
||||||
|
|
||||||
|
- Advancing or reversing the turn order
|
||||||
|
- Conceding or unconceding
|
||||||
|
- Changing the active phase
|
||||||
|
- Leaving the game
|
||||||
|
- Sending chat messages
|
||||||
|
|
||||||
|
These commands are wrapped in `PendingCommand` instances so their lifecycle and
|
||||||
|
responses can be tracked.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Processing incoming game events
|
||||||
|
|
||||||
|
Incoming server messages arrive as a `GameEventContainer`.
|
||||||
|
`GameEventHandler` is responsible for:
|
||||||
|
|
||||||
|
- Emitting lifecycle signals before and after processing
|
||||||
|
- Dispatching each event to the correct handler
|
||||||
|
- Forwarding player-scoped events to `PlayerEventHandler` instances
|
||||||
|
- Handling spectator-only and game-global events directly
|
||||||
|
|
||||||
|
This design keeps networking concerns isolated from game logic and UI code.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Managing global game state transitions
|
||||||
|
|
||||||
|
Certain events affect the entire game state and require coordinated updates across
|
||||||
|
multiple subsystems. Examples include:
|
||||||
|
|
||||||
|
- Full game state synchronization
|
||||||
|
- Active player or phase changes
|
||||||
|
- Game host changes
|
||||||
|
- Game closure
|
||||||
|
- Turn reversal
|
||||||
|
|
||||||
|
`GameEventHandler` ensures these events are processed in a consistent order and
|
||||||
|
that all interested systems are notified via Qt signals.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. Emitting UI and logging signals
|
||||||
|
|
||||||
|
Rather than directly manipulating UI widgets, `GameEventHandler` emits
|
||||||
|
high-level signals that are consumed by:
|
||||||
|
|
||||||
|
- Game widgets
|
||||||
|
- Player and spectator lists
|
||||||
|
- Message and event logs
|
||||||
|
- Status indicators (ready state, deck selection, connection state)
|
||||||
|
|
||||||
|
This keeps the handler independent of concrete UI implementations.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Relationship to PlayerEventHandler
|
||||||
|
|
||||||
|
`GameEventHandler` and `PlayerEventHandler` work together but have distinct roles:
|
||||||
|
|
||||||
|
| GameEventHandler | PlayerEventHandler |
|
||||||
|
|------------------|--------------------|
|
||||||
|
| Global game state | Per-player state |
|
||||||
|
| Turn / phase flow | Zones and cards |
|
||||||
|
| Player join/leave | Player actions |
|
||||||
|
| Spectator events | Player-specific events |
|
||||||
|
| Chat dispatch | Card and zone updates |
|
||||||
|
|
||||||
|
When a server event is associated with a specific player, `GameEventHandler`
|
||||||
|
routes it to the corresponding `PlayerEventHandler`. Events without a player
|
||||||
|
context are handled directly.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Event Processing Flow
|
||||||
|
|
||||||
|
A typical incoming event flow looks like this:
|
||||||
|
|
||||||
|
1. `AbstractClient` receives a `GameEventContainer`
|
||||||
|
2. `GameEventHandler::processGameEventContainer()` is called
|
||||||
|
3. `containerProcessingStarted()` is emitted
|
||||||
|
4. Each event is:
|
||||||
|
- Handled directly **or**
|
||||||
|
- Forwarded to a `PlayerEventHandler`
|
||||||
|
5. Logging and UI signals are emitted as needed
|
||||||
|
6. `containerProcessingDone()` is emitted
|
||||||
|
|
||||||
|
This structured flow makes it easy to:
|
||||||
|
|
||||||
|
- Suppress UI updates during replays
|
||||||
|
- Handle reconnections cleanly
|
||||||
|
- Detect flood protection or error states
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Command Lifecycle
|
||||||
|
|
||||||
|
Outgoing commands follow a similar structured path:
|
||||||
|
|
||||||
|
1. UI action triggers a `handle*()` method
|
||||||
|
2. A protobuf command is constructed
|
||||||
|
3. The command is wrapped in a `PendingCommand`
|
||||||
|
4. `sendGameCommand()` sends it to the server
|
||||||
|
5. `commandFinished()` receives the response
|
||||||
|
6. Errors or flood conditions are handled centrally
|
||||||
|
|
||||||
|
This approach avoids duplicated error handling across UI code.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Design Goals
|
||||||
|
|
||||||
|
`GameEventHandler` is designed to be:
|
||||||
|
|
||||||
|
- **Centralized** – one entry point for all game-wide events
|
||||||
|
- **UI-agnostic** – communicates via signals, not widgets
|
||||||
|
- **Predictable** – well-defined event ordering and lifecycle
|
||||||
|
- **Composable** – works in concert with `PlayerEventHandler`
|
||||||
|
- **Testable** – logic is separated from rendering
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Related Classes
|
||||||
|
|
||||||
|
- @ref GameEventHandler
|
||||||
|
- @ref PlayerEventHandler
|
||||||
|
- `GameEventContainer`
|
||||||
|
- `PendingCommand`
|
||||||
|
- `AbstractClient`
|
||||||
|
- `AbstractGame`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- @ref GameLogic
|
||||||
|
- @ref PlayerEventHandler
|
||||||
|
- @ref GameState
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
@page developer_reference_network_client Client Networking (Overview)
|
||||||
|
|
||||||
|
The clients response to various network protocol events and associated handling are described here.
|
||||||
|
|
||||||
|
For information about game scoped events, see:
|
||||||
|
|
||||||
|
- @subpage game_event_handler
|
||||||
|
|
||||||
|
Certain game scoped events may be forwarded to player based handlers. For more information, see:
|
||||||
|
|
||||||
|
- @subpage player_event_handler
|
||||||
|
|
@ -0,0 +1,199 @@
|
||||||
|
@page player_event_handler PlayerEventHandler
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
`PlayerEventHandler` is responsible for applying **player-scoped game events**
|
||||||
|
to a single `Player` instance. These events modify the player’s board state,
|
||||||
|
zones, cards, counters, arrows, and associated UI and logging output.
|
||||||
|
|
||||||
|
Each `PlayerEventHandler` instance is bound **1:1 to a Player** and is invoked
|
||||||
|
exclusively by @ref GameEventHandler after basic routing and validation of
|
||||||
|
incoming server events.
|
||||||
|
|
||||||
|
This class represents the lowest-level authoritative application of game state
|
||||||
|
changes on the client.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Scope and Authority
|
||||||
|
|
||||||
|
`PlayerEventHandler` operates under the following guarantees:
|
||||||
|
|
||||||
|
- All incoming events are **authoritative** and already validated by the server
|
||||||
|
- Events refer to valid players, zones, and card identifiers
|
||||||
|
- Ordering is guaranteed by the server and preserved by `GameEventHandler`
|
||||||
|
|
||||||
|
As a result, the handler does **not** perform rule validation or permission
|
||||||
|
checks. Its responsibility is to *apply* state, not *decide* legality.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Responsibilities
|
||||||
|
|
||||||
|
### 1. Applying player-specific state changes
|
||||||
|
|
||||||
|
The primary responsibility of `PlayerEventHandler` is to mutate player-owned
|
||||||
|
state, including:
|
||||||
|
|
||||||
|
- Cards (`CardItem`)
|
||||||
|
- Zones (`CardZoneLogic`)
|
||||||
|
- Counters (card-level and player-level)
|
||||||
|
- Attachments and arrows
|
||||||
|
- Zone configuration flags (reveal / peek behavior)
|
||||||
|
|
||||||
|
Many handlers update both **logical state** and **visual/UI state** in tandem.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Coordinating complex card movement
|
||||||
|
|
||||||
|
Some events—most notably card movement—require coordinated updates across
|
||||||
|
multiple systems. For example, `eventMoveCard()`:
|
||||||
|
|
||||||
|
- Removes the card from the source zone
|
||||||
|
- Updates ownership, visibility, and identity
|
||||||
|
- Handles attachments and arrow cleanup
|
||||||
|
- Emits undo-draw or move logs
|
||||||
|
- Inserts the card into the destination zone
|
||||||
|
- Updates menus, hover state, and graphics
|
||||||
|
|
||||||
|
This makes `PlayerEventHandler` intentionally stateful and tightly coupled to
|
||||||
|
the board implementation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Emitting logging signals
|
||||||
|
|
||||||
|
Rather than writing directly to logs or widgets, `PlayerEventHandler` emits
|
||||||
|
structured Qt signals describing *what happened*, including:
|
||||||
|
|
||||||
|
- Chat messages
|
||||||
|
- Card movement
|
||||||
|
- Shuffles and randomization
|
||||||
|
- Reveals and peeks
|
||||||
|
- Counter and attribute changes
|
||||||
|
|
||||||
|
These signals are consumed by logging systems and UI components, keeping
|
||||||
|
presentation concerns out of the handler.
|
||||||
|
|
||||||
|
Logging signals may be emitted **before or after mutation**, depending on
|
||||||
|
whether later changes would invalidate log data (e.g. card identity).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. Handling cross-player interactions
|
||||||
|
|
||||||
|
Although bound to a single player, some events necessarily affect other
|
||||||
|
players’ state, including:
|
||||||
|
|
||||||
|
- Moving cards between players
|
||||||
|
- Attaching cards to another player’s permanents
|
||||||
|
- Creating arrows targeting other players or cards
|
||||||
|
|
||||||
|
In these cases, `PlayerEventHandler` performs the minimal required mutation
|
||||||
|
while respecting ownership boundaries enforced elsewhere.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Event Dispatch Model
|
||||||
|
|
||||||
|
`PlayerEventHandler` exposes a single public entry point:
|
||||||
|
|
||||||
|
- `processGameEvent()`
|
||||||
|
|
||||||
|
This method:
|
||||||
|
|
||||||
|
1. Receives a generic `GameEvent`
|
||||||
|
2. Switches on `GameEventType`
|
||||||
|
3. Extracts the appropriate protobuf extension
|
||||||
|
4. Forwards the event to a typed handler
|
||||||
|
|
||||||
|
This keeps the event routing centralized and makes it easy to audit coverage
|
||||||
|
when new game events are introduced.
|
||||||
|
|
||||||
|
Unhandled events are logged as warnings.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Event Categories
|
||||||
|
|
||||||
|
For clarity, event handlers are grouped conceptually into:
|
||||||
|
|
||||||
|
- **Chat and randomization**
|
||||||
|
- Chat messages
|
||||||
|
- Shuffles
|
||||||
|
- Dice rolls
|
||||||
|
|
||||||
|
- **Arrows and targeting**
|
||||||
|
- Create / delete arrows
|
||||||
|
|
||||||
|
- **Card and token creation**
|
||||||
|
- Token generation
|
||||||
|
- Counter creation
|
||||||
|
|
||||||
|
- **Card attributes and counters**
|
||||||
|
- Tapped state
|
||||||
|
- Power/toughness
|
||||||
|
- Annotations
|
||||||
|
- Card- and player-level counters
|
||||||
|
|
||||||
|
- **Zone-level operations**
|
||||||
|
- Card movement
|
||||||
|
- Zone dumps
|
||||||
|
- Card destruction
|
||||||
|
- Attachments
|
||||||
|
|
||||||
|
- **Draw and reveal**
|
||||||
|
- Drawing cards
|
||||||
|
- Reveals, peeks, and reveal windows
|
||||||
|
|
||||||
|
- **Zone configuration**
|
||||||
|
- Always-reveal and always-look-at-top-card flags
|
||||||
|
|
||||||
|
This grouping mirrors the structure of the header file and reflects the
|
||||||
|
conceptual responsibilities of the class.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Relationship to GameEventHandler
|
||||||
|
|
||||||
|
`PlayerEventHandler` is never instantiated or invoked directly by UI code.
|
||||||
|
Instead:
|
||||||
|
|
||||||
|
1. `GameEventHandler` receives a `GameEventContainer`
|
||||||
|
2. Player-scoped events are routed to the appropriate `PlayerEventHandler`
|
||||||
|
3. Global or spectator events are handled elsewhere
|
||||||
|
|
||||||
|
This separation keeps game-wide logic decoupled from player board state and
|
||||||
|
makes reconnection and replay handling simpler.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Design Intent
|
||||||
|
|
||||||
|
`PlayerEventHandler` is designed to be:
|
||||||
|
|
||||||
|
- **Authoritative** – applies server state exactly as received
|
||||||
|
- **Stateful** – maintains consistency across cards, zones, and UI
|
||||||
|
- **Explicit** – one handler per event type
|
||||||
|
- **UI-aware** – updates views and menus as part of state mutation
|
||||||
|
- **Auditable** – easy to trace what code handles which event
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Related Classes
|
||||||
|
|
||||||
|
- @ref PlayerEventHandler
|
||||||
|
- @ref GameEventHandler
|
||||||
|
- `Player`
|
||||||
|
- `CardItem`
|
||||||
|
- `CardZoneLogic`
|
||||||
|
- `GameEvent`
|
||||||
|
- `GameEventContext`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- @ref GameLogicPlayers
|
||||||
|
- @ref GameLogic
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
@page developer_reference_network_overview Network (Overview)
|
||||||
|
|
||||||
|
This page provides information about the networking performed by the client and server.
|
||||||
|
|
||||||
|
For information about the protocol, see @subpage developer_reference_protocol
|
||||||
|
|
||||||
|
For information about the clients response to and handling of protocol messages, see @subpage developer_reference_network_client
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
@page developer_reference_protocol Protocol (Overview)
|
||||||
|
|
||||||
|
For an overview of the protocol used by the Cockatrice client and server, see:
|
||||||
|
|
||||||
|
- @subpage developer_reference_protocol_overview
|
||||||
|
- @subpage protocol_game_command
|
||||||
|
|
||||||
|
For client → server communication, see:
|
||||||
|
|
||||||
|
- @subpage protocol_command_container
|
||||||
|
|
||||||
|
For server → client communication, see:
|
||||||
|
|
||||||
|
- @subpage protocol_server_message
|
||||||
|
- @subpage protocol_response
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
@page protocol_command_container CommandContainer (Protocol Concept)
|
||||||
|
|
||||||
|
@section cc_overview Overview
|
||||||
|
|
||||||
|
CommandContainer is the client-to-server message envelope used for all
|
||||||
|
client requests in the Cockatrice protocol.
|
||||||
|
|
||||||
|
Every client-initiated action is transmitted as a CommandContainer.
|
||||||
|
The server never sends CommandContainer messages.
|
||||||
|
|
||||||
|
This is a protocol-level abstraction and should not be confused with the
|
||||||
|
generated protobuf accessors or wire-level encoding.
|
||||||
|
|
||||||
|
@section cc_lifecycle Lifetime and Ownership
|
||||||
|
|
||||||
|
- CommandContainers are created by clients and consumed by the server.
|
||||||
|
- Each container represents one logical request.
|
||||||
|
- Containers are processed atomically and in order of arrival.
|
||||||
|
|
||||||
|
A container may generate:
|
||||||
|
- Exactly one RESPONSE message, and
|
||||||
|
- Zero or more EVENT messages.
|
||||||
|
|
||||||
|
@section cc_cmd_id Command Identification
|
||||||
|
|
||||||
|
The @c cmd_id field is a client-assigned identifier used to correlate
|
||||||
|
responses with requests.
|
||||||
|
|
||||||
|
Rules:
|
||||||
|
- @c cmd_id is optional but strongly recommended
|
||||||
|
- The server echoes @c cmd_id only in RESPONSE messages
|
||||||
|
- EVENT messages are never associated with a @c cmd_id
|
||||||
|
|
||||||
|
The server does not enforce uniqueness of @c cmd_id values.
|
||||||
|
|
||||||
|
@section cc_context Command Context
|
||||||
|
|
||||||
|
Certain command domains require additional context:
|
||||||
|
|
||||||
|
- Room commands require @c room_id
|
||||||
|
- Game commands require @c game_id
|
||||||
|
|
||||||
|
Context fields are ignored for command domains that do not require them.
|
||||||
|
|
||||||
|
If a required context field is missing or invalid, the server responds with
|
||||||
|
@c RespContextError.
|
||||||
|
|
||||||
|
@section cc_invariants Invariants
|
||||||
|
|
||||||
|
The following rules are enforced by the server:
|
||||||
|
|
||||||
|
- Exactly one command domain must be populated
|
||||||
|
- Commands may be batched only within the same domain
|
||||||
|
- Context fields must match the active command domain
|
||||||
|
|
||||||
|
Violations of these rules result in @c RespInvalidCommand.
|
||||||
|
|
||||||
|
@section cc_domains Command Domains
|
||||||
|
|
||||||
|
CommandContainer supports the following mutually exclusive command domains:
|
||||||
|
|
||||||
|
- Session commands
|
||||||
|
- Authentication
|
||||||
|
- User discovery
|
||||||
|
- Private messaging
|
||||||
|
|
||||||
|
- Room commands
|
||||||
|
- Chat
|
||||||
|
- Game creation
|
||||||
|
- Room membership management
|
||||||
|
|
||||||
|
- Game commands
|
||||||
|
- In-game actions
|
||||||
|
- State mutations
|
||||||
|
|
||||||
|
- Moderator commands
|
||||||
|
- User moderation
|
||||||
|
- Room moderation
|
||||||
|
|
||||||
|
- Admin commands
|
||||||
|
- Server administration
|
||||||
|
|
||||||
|
@section cc_batching Command Batching
|
||||||
|
|
||||||
|
A CommandContainer may contain multiple commands of the same domain.
|
||||||
|
|
||||||
|
Batching guarantees:
|
||||||
|
- Commands are processed in the order they appear in the container
|
||||||
|
- All commands in the batch share the same context
|
||||||
|
|
||||||
|
Partial failure behavior is implementation-defined and may vary by domain.
|
||||||
|
|
||||||
|
@section cc_dispatch Dispatch
|
||||||
|
|
||||||
|
CommandContainers are dispatched by
|
||||||
|
Server_ProtocolHandler::processCommandContainer().
|
||||||
|
|
||||||
|
Dispatch is performed by inspecting which command domain is populated.
|
||||||
|
Only the first populated domain is considered.
|
||||||
|
|
||||||
|
@section cc_errors Error Handling
|
||||||
|
|
||||||
|
Common error responses include:
|
||||||
|
- @c RespLoginNeeded – client is not authenticated
|
||||||
|
- @c RespInvalidCommand – malformed container or invalid domain usage
|
||||||
|
- @c RespContextError – missing or invalid room/game context
|
||||||
|
|
||||||
|
@section cc_related Related Concepts
|
||||||
|
|
||||||
|
- @ref protocol_server_message "ServerMessage"
|
||||||
|
- @ref protocol_client_states "Client State Machine"
|
||||||
|
|
||||||
|
@see Server_ProtocolHandler::processCommandContainer
|
||||||
|
|
||||||
|
|
@ -0,0 +1,529 @@
|
||||||
|
@page protocol_game_command GameCommand (Protocol Concept)
|
||||||
|
|
||||||
|
# Game Commands Reference
|
||||||
|
|
||||||
|
This document describes game-level commands (`GameCommandType`) and how they are
|
||||||
|
handled across the server and client.
|
||||||
|
|
||||||
|
Flow overview:
|
||||||
|
|
||||||
|
Client
|
||||||
|
→ GameCommand
|
||||||
|
→ Server command handler (`Server_Player`, `Server_AbstractParticipant`, or `Server_Game`)
|
||||||
|
→ GameEvent(s)
|
||||||
|
→ PlayerEventHandler::event*
|
||||||
|
|
||||||
|
## Command Mapping
|
||||||
|
|
||||||
|
### `GAME_SAY` (1002)
|
||||||
|
|
||||||
|
**Purpose:** Send a chat message during a game.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_AbstractParticipant::cmdGameSay`
|
||||||
|
- Validates spectator chat permissions
|
||||||
|
- Applies chat flood protection
|
||||||
|
- Emits `Event_GameSay`
|
||||||
|
- Logs the message to the server database
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventGameSay`
|
||||||
|
- Adds the chat message to the game log
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `SHUFFLE` (1003)
|
||||||
|
|
||||||
|
**Purpose:** Shuffle a card zone (usually library).
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_Player::cmdShuffle`
|
||||||
|
- Only allows shuffling the deck zone
|
||||||
|
- Rejects if the game has not started or the player has conceded
|
||||||
|
- Supports partial-range shuffles (`start` / `end`)
|
||||||
|
- Emits `Event_Shuffle`
|
||||||
|
- Re-reveals the top card if the deck is being tracked
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventShuffle`
|
||||||
|
- Closes affected library views
|
||||||
|
- Clears any revealed top card if necessary
|
||||||
|
- Updates deck graphics
|
||||||
|
- Logs the shuffle
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `ROLL_DIE` (1005)
|
||||||
|
|
||||||
|
**Purpose:** Roll one or more dice.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- Computes random die results
|
||||||
|
- Emits `Event_RollDie`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventRollDie`
|
||||||
|
- Displays the sorted roll results in the game log
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `DRAW_CARDS` (1006)
|
||||||
|
|
||||||
|
**Purpose:** Draw cards from deck.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_Player::cmdDrawCards`
|
||||||
|
- Rejects if the game has not started or the player has conceded
|
||||||
|
- Moves cards from deck to hand
|
||||||
|
- Sends full card information privately to the drawing player
|
||||||
|
- Sends only the draw count to all other players
|
||||||
|
- Tracks drawn cards for undo
|
||||||
|
- Updates revealed-top-card state when necessary
|
||||||
|
- Emits `Event_DrawCards`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventDrawCards`
|
||||||
|
- Moves cards from library to hand
|
||||||
|
- Reveals card identities only when included in the event
|
||||||
|
- Updates both zones
|
||||||
|
- Logs the draw
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `UNDO_DRAW` (1007)
|
||||||
|
|
||||||
|
**Purpose:** Undo a previous draw.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_Player::cmdUndoDraw`
|
||||||
|
- Rejects if the game has not started or the player has conceded
|
||||||
|
- Uses the tracked draw history (`lastDrawList`)
|
||||||
|
- Moves the most recently drawable card from hand back to the top of the deck
|
||||||
|
- Emits `Event_GameLogNotice` if undo is no longer possible
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- Processed as a normal `MOVE_CARD`
|
||||||
|
- Detects `Context_UndoDraw`
|
||||||
|
- Logs the undo draw instead of a normal move
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `FLIP_CARD` (1008)
|
||||||
|
|
||||||
|
**Purpose:** Flip a card face up or face down.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- Updates the card's face-down state
|
||||||
|
- Reveals identity when turning face up
|
||||||
|
- Emits `Event_FlipCard`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventFlipCard`
|
||||||
|
- Updates the card identity when revealed
|
||||||
|
- Changes face-up / face-down state
|
||||||
|
- Updates card menus
|
||||||
|
- Logs the flip
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `ATTACH_CARD` (1009)
|
||||||
|
|
||||||
|
**Purpose:** Attach one card to another.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- Updates attachment relationships
|
||||||
|
- Emits `Event_AttachCard`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventAttachCard`
|
||||||
|
- Updates parent/child attachment links
|
||||||
|
- Reorganizes affected zones
|
||||||
|
- Logs attach or detach operations
|
||||||
|
- Refreshes card actions
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `CREATE_TOKEN` (1010)
|
||||||
|
|
||||||
|
**Purpose:** Create a token card.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- Creates a new token card
|
||||||
|
- Emits `Event_CreateToken`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventCreateToken`
|
||||||
|
- Creates the token object
|
||||||
|
- Applies token properties (PT, color, annotation, face-down state)
|
||||||
|
- Adds it to the requested zone
|
||||||
|
- Logs token creation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `CREATE_ARROW` (1011)
|
||||||
|
|
||||||
|
**Purpose:** Create a visual arrow.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- Creates a visual arrow
|
||||||
|
- Emits `Event_CreateArrow`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventCreateArrow`
|
||||||
|
- Creates the arrow graphics
|
||||||
|
- Resolves endpoint card names
|
||||||
|
- Logs arrow creation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `DELETE_ARROW` (1012)
|
||||||
|
|
||||||
|
**Purpose:** Remove a visual arrow.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- Removes an existing arrow
|
||||||
|
- Emits `Event_DeleteArrow`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventDeleteArrow`
|
||||||
|
- Removes the arrow graphics
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `SET_CARD_ATTR` (1013)
|
||||||
|
|
||||||
|
**Purpose:** Set a card attribute.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- Updates one or more card attributes
|
||||||
|
- Emits `Event_SetCardAttr`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventSetCardAttr`
|
||||||
|
- Updates tapped state, color, annotation, power/toughness, face-down state, attacking state, and related visuals
|
||||||
|
- Logs attribute changes where appropriate
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `SET_CARD_COUNTER` (1014)
|
||||||
|
|
||||||
|
**Purpose:** Set a card counter.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- Updates the specified card counter
|
||||||
|
- Emits `Event_SetCardCounter`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventSetCardCounter`
|
||||||
|
- Updates the displayed counter value
|
||||||
|
- Refreshes card actions
|
||||||
|
- Logs the counter change
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `INC_CARD_COUNTER` (1015)
|
||||||
|
|
||||||
|
**Purpose:** Increment a card counter.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- Normalizes to a set-counter operation
|
||||||
|
- Emits `Event_SetCardCounter`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- Processed identically to `SET_CARD_COUNTER`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `READY_START` (1016)
|
||||||
|
|
||||||
|
**Purpose:** Mark player as ready.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- Marks the player as ready
|
||||||
|
- Starts the game once all required players are ready
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- Reflected through updated game state events
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `CONCEDE` (1017)
|
||||||
|
|
||||||
|
**Purpose:** Concede the game.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- Marks the player as conceded
|
||||||
|
- Returns borrowed cards where appropriate
|
||||||
|
- Ends the game if only one player remains
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- Reflected through updated game state events
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `INC_COUNTER` (1018)
|
||||||
|
|
||||||
|
**Purpose:** Increment a player counter.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_Player::cmdIncCounter`
|
||||||
|
- Rejects if the game has not started or the player has conceded
|
||||||
|
- Updates the counter value
|
||||||
|
- Emits `Event_SetCounter` only if the value changed
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventSetCounter`
|
||||||
|
- Updates the displayed player counter
|
||||||
|
- Logs the change
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `CREATE_COUNTER` (1019)
|
||||||
|
|
||||||
|
**Purpose:** Create a player counter.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_Player::cmdCreateCounter`
|
||||||
|
- Rejects if the game has not started or the player has conceded
|
||||||
|
- Allocates a new counter ID
|
||||||
|
- Creates the counter
|
||||||
|
- Emits `Event_CreateCounter`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventCreateCounter`
|
||||||
|
- Creates the local player counter
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `SET_COUNTER` (1020)
|
||||||
|
|
||||||
|
**Purpose:** Set a player counter value.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_Player::cmdSetCounter`
|
||||||
|
- Rejects if the game has not started or the player has conceded
|
||||||
|
- Updates the counter value
|
||||||
|
- Emits `Event_SetCounter` only if the value changed
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventSetCounter`
|
||||||
|
- Updates the counter value
|
||||||
|
- Logs the change
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `DEL_COUNTER` (1021)
|
||||||
|
|
||||||
|
**Purpose:** Delete a player counter.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_Player::cmdDelCounter`
|
||||||
|
- Rejects if the game has not started or the player has conceded
|
||||||
|
- Deletes the counter
|
||||||
|
- Emits `Event_DelCounter`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventDelCounter`
|
||||||
|
- Removes the counter
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `NEXT_TURN` (1022)
|
||||||
|
|
||||||
|
**Purpose:** Advance to the next turn.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_Player::cmdNextTurn`
|
||||||
|
- Rejects if the game has not started
|
||||||
|
- Conceded players cannot advance turns unless acting as a judge
|
||||||
|
- Calls `Server_Game::nextTurn()`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- Reflected through subsequent active-player and active-phase events
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `SET_ACTIVE_PHASE` (1023)
|
||||||
|
|
||||||
|
**Purpose:** Set active phase.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_Player::cmdSetActivePhase`
|
||||||
|
- Rejects if the game has not started
|
||||||
|
- Judges may change the phase at any time
|
||||||
|
- Normal players may only change the phase during their own active turn
|
||||||
|
- Calls `Server_Game::setActivePhase()`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- Reflected through updated phase events
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `DUMP_ZONE` (1024)
|
||||||
|
|
||||||
|
**Purpose:** Dump zone contents.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- Generates a zone summary
|
||||||
|
- Emits `Event_DumpZone`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventDumpZone`
|
||||||
|
- Logs the zone contents summary
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `REVEAL_CARDS` (1026)
|
||||||
|
|
||||||
|
**Purpose:** Reveal specific cards.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- Reveals cards to one or more players
|
||||||
|
- Emits `Event_RevealCards`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventRevealCards`
|
||||||
|
- Reveals cards in-place or in a reveal window
|
||||||
|
- Supports temporary peeks
|
||||||
|
- Updates revealed top cards
|
||||||
|
- Logs the reveal
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `MOVE_CARD` (1027)
|
||||||
|
|
||||||
|
**Purpose:** Move a card between zones.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- Moves cards between zones
|
||||||
|
- Updates ownership and attachments as needed
|
||||||
|
- Emits `Event_MoveCard`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventMoveCard`
|
||||||
|
- Moves the card between zones
|
||||||
|
- Updates ownership, attachments, IDs and revealed information
|
||||||
|
- Handles undo-draw context
|
||||||
|
- Refreshes menus and zone layouts
|
||||||
|
- Logs the move
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `SET_SIDEBOARD_PLAN` (1028)
|
||||||
|
|
||||||
|
**Purpose:** Set sideboard configuration.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_Player::cmdSetSideboardPlan`
|
||||||
|
- Allowed only before readying for the game
|
||||||
|
- Requires a loaded deck
|
||||||
|
- Requires sideboarding to be unlocked
|
||||||
|
- Stores the current sideboard plan
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- No game event is generated
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `DECK_SELECT` (1029)
|
||||||
|
|
||||||
|
**Purpose:** Select a deck.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_Player::cmdDeckSelect`
|
||||||
|
- Allowed only before the game starts
|
||||||
|
- Loads a deck from either the database or serialized deck data
|
||||||
|
- Locks sideboarding
|
||||||
|
- Updates player properties
|
||||||
|
- Emits `Event_PlayerPropertiesChanged`
|
||||||
|
- Attaches `Context_DeckSelect`
|
||||||
|
- Returns the selected deck in the command response
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- Reflected through updated player properties and command response
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `SET_SIDEBOARD_LOCK` (1030)
|
||||||
|
|
||||||
|
**Purpose:** Lock or unlock sideboarding.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_Player::cmdSetSideboardLock`
|
||||||
|
- Allowed only before readying
|
||||||
|
- Toggles sideboard locking
|
||||||
|
- Clears pending sideboard plans when locking
|
||||||
|
- Emits `Event_PlayerPropertiesChanged`
|
||||||
|
- Attaches `Context_SetSideboardLock`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- Reflected through updated player properties
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `CHANGE_ZONE_PROPERTIES` (1031)
|
||||||
|
|
||||||
|
**Purpose:** Change zone properties.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_Player::cmdChangeZoneProperties`
|
||||||
|
- Delegates to the abstract implementation
|
||||||
|
- Updates top-card revelation if required
|
||||||
|
- Emits `Event_ChangeZoneProperties`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- `PlayerEventHandler::eventChangeZoneProperties`
|
||||||
|
- Updates always-reveal-top-card and always-look-at-top-card settings
|
||||||
|
- Logs property changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `UNCONCEDE` (1032)
|
||||||
|
|
||||||
|
**Purpose:** Undo a concede.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- Restores the player's active status
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- Reflected through updated game state events
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `JUDGE` (1033)
|
||||||
|
|
||||||
|
**Purpose:** Execute commands on behalf of another player.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_AbstractParticipant::cmdJudge`
|
||||||
|
- Requires judge privileges
|
||||||
|
- Executes embedded commands as the selected player
|
||||||
|
- Marks resulting events as judge-forced
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- Transparent; resulting events are processed normally
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `REVERSE_TURN` (1034)
|
||||||
|
|
||||||
|
**Purpose:** Reverse turn order.
|
||||||
|
|
||||||
|
**Server:**
|
||||||
|
- `Server_Player::cmdReverseTurn`
|
||||||
|
- Conceded non-judge players cannot use the command
|
||||||
|
- Delegates to `Server_AbstractParticipant::cmdReverseTurn`
|
||||||
|
- Toggles turn order
|
||||||
|
- Emits `Event_ReverseTurn`
|
||||||
|
|
||||||
|
**Client:**
|
||||||
|
- Reflected by subsequent active-player progression
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Game commands are handled by `Server_Player`, `Server_AbstractParticipant`, or `Server_Game`, depending on the command.
|
||||||
|
- Only commands that emit `GameEvent`s produce corresponding `PlayerEventHandler` callbacks.
|
||||||
|
- Some commands modify server state without generating a dedicated client event.
|
||||||
|
- Judge commands are transport wrappers that execute other game commands on behalf of another player.
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
@page developer_reference_protocol_overview Protocol (Overview)
|
||||||
|
|
||||||
|
# Cockatrice Server Protocol – Overview
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
This document describes the Cockatrice client/server protocol as implemented
|
||||||
|
by the Cockatrice server. It is intended for developers implementing clients
|
||||||
|
or modifying the server.
|
||||||
|
|
||||||
|
The protocol is **stateful**, **event-driven**, and **asynchronous**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## High-Level Properties
|
||||||
|
|
||||||
|
- Encoding: Google Protocol Buffers
|
||||||
|
- Transport: TCP or WebSocket (transport-agnostic at protocol level)
|
||||||
|
- Directionality:
|
||||||
|
- Clients send `CommandContainer`
|
||||||
|
- Server sends `ServerMessage`
|
||||||
|
- Responses and events are interleaved
|
||||||
|
- Clients must handle unsolicited events at any time
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Message Envelopes
|
||||||
|
|
||||||
|
### Client → Server: CommandContainer
|
||||||
|
|
||||||
|
A `CommandContainer` represents one logical client request.
|
||||||
|
|
||||||
|
Protocol invariants:
|
||||||
|
- Exactly one command domain may be used per container
|
||||||
|
- Multiple commands of the same domain may be batched
|
||||||
|
- Context is provided via `room_id` or `game_id` when required
|
||||||
|
|
||||||
|
Command domains:
|
||||||
|
- Session commands
|
||||||
|
- Room commands
|
||||||
|
- Game commands
|
||||||
|
- Moderator commands
|
||||||
|
- Admin commands
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Server → Client: ServerMessage
|
||||||
|
|
||||||
|
A `ServerMessage` represents either:
|
||||||
|
- A response to a command (`RESPONSE`)
|
||||||
|
- An unsolicited event (`*_EVENT`)
|
||||||
|
|
||||||
|
Protocol invariants:
|
||||||
|
- Events may be delivered before or after responses
|
||||||
|
- Responses reference the original command via `cmd_id`
|
||||||
|
- Events are never correlated to a command
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Asynchronous Model
|
||||||
|
|
||||||
|
Clients MUST NOT assume request/response ordering.
|
||||||
|
|
||||||
|
Example valid sequence:
|
||||||
|
|
||||||
|
1. Client sends JOIN_ROOM
|
||||||
|
2. Server sends room chat history events
|
||||||
|
3. Server sends room join notifications
|
||||||
|
4. Server sends JOIN_ROOM response
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Versioning
|
||||||
|
|
||||||
|
The server reports a protocol version during connection initialization.
|
||||||
|
Clients MUST verify compatibility before sending commands.
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
@page protocol_response Response (Protocol Concept)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
`Response` is the server-to-client message sent immediately after a command, using the same `cmd_id` to link to the originating command.
|
||||||
|
It provides a `Response::ResponseCode` and optionally a `Response::ResponseType` to guide client handling.
|
||||||
|
|
||||||
|
## Fields
|
||||||
|
|
||||||
|
- **cmd_id** (`uint64`, required) — Command ID this response corresponds to
|
||||||
|
- **response_code** (`Response::ResponseCode`, optional) — Outcome of the command
|
||||||
|
|
||||||
|
## Response Codes
|
||||||
|
|
||||||
|
All possible outcome codes are defined in Response::ResponseCode
|
||||||
|
|
||||||
|
These describe the result of the command, e.g., success, failure, or special conditions like bans or registration requirements.
|
||||||
|
|
||||||
|
## Response Types
|
||||||
|
|
||||||
|
Responses are routed according to Response::ResponseType
|
||||||
|
|
||||||
|
Each `ResponseType` corresponds to a high-level category, like `JOIN_ROOM` or `DECK_UPLOAD`.
|
||||||
|
|
||||||
|
## Extensions
|
||||||
|
|
||||||
|
- Protobuf extensions from 100 to max are reserved for future use
|
||||||
|
|
@ -0,0 +1,171 @@
|
||||||
|
@page protocol_server_message ServerMessage (Protocol Concept)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
`ServerMessage` is the server-to-client message envelope used for all
|
||||||
|
communication originating from the Cockatrice server.
|
||||||
|
|
||||||
|
The server never sends `CommandContainer` messages, and clients never send
|
||||||
|
`ServerMessage` messages.
|
||||||
|
|
||||||
|
A `ServerMessage` represents either:
|
||||||
|
|
||||||
|
- A direct response to a client command, or
|
||||||
|
- An unsolicited event emitted by the server
|
||||||
|
|
||||||
|
This document describes `ServerMessage` as a protocol-level concept.
|
||||||
|
It should not be confused with generated protobuf accessors or wire-level
|
||||||
|
encoding details.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lifetime and Delivery
|
||||||
|
|
||||||
|
`ServerMessage` instances are emitted by the server and delivered
|
||||||
|
asynchronously to clients.
|
||||||
|
|
||||||
|
Delivery guarantees:
|
||||||
|
|
||||||
|
- Messages are delivered in the order sent by the server
|
||||||
|
- Messages may be delivered at any time
|
||||||
|
- Events may be delivered before or after responses
|
||||||
|
|
||||||
|
Clients **must** be prepared to handle `ServerMessage` objects at all times,
|
||||||
|
regardless of pending requests.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Message Type
|
||||||
|
|
||||||
|
Each `ServerMessage` contains **exactly one payload**, identified by the
|
||||||
|
`message_type` field.
|
||||||
|
|
||||||
|
The following message types are supported:
|
||||||
|
|
||||||
|
- `RESPONSE`
|
||||||
|
- `SESSION_EVENT`
|
||||||
|
- `ROOM_EVENT`
|
||||||
|
- `GAME_EVENT_CONTAINER`
|
||||||
|
|
||||||
|
A message containing multiple payloads or an unknown type is considered
|
||||||
|
malformed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## RESPONSE
|
||||||
|
|
||||||
|
`RESPONSE` messages are direct replies to client-issued `CommandContainer`
|
||||||
|
messages.
|
||||||
|
|
||||||
|
Characteristics:
|
||||||
|
|
||||||
|
- Contain a `Response` payload
|
||||||
|
- Echo the client-assigned `cmd_id`
|
||||||
|
- Indicate success or failure of the request
|
||||||
|
|
||||||
|
A single `CommandContainer` results in **at most one** `RESPONSE`.
|
||||||
|
|
||||||
|
`RESPONSE` messages may be preceded or followed by event messages.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Events
|
||||||
|
|
||||||
|
Event messages are unsolicited notifications emitted by the server.
|
||||||
|
|
||||||
|
Event message types include:
|
||||||
|
|
||||||
|
- `SESSION_EVENT`
|
||||||
|
- `ROOM_EVENT`
|
||||||
|
- `GAME_EVENT_CONTAINER`
|
||||||
|
|
||||||
|
Event messages:
|
||||||
|
|
||||||
|
- Are not correlated to a specific client command
|
||||||
|
- Do not include a `cmd_id`
|
||||||
|
- May be delivered at any time
|
||||||
|
|
||||||
|
Clients **must** process events independently of responses.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Event Scopes
|
||||||
|
|
||||||
|
### Session Events
|
||||||
|
|
||||||
|
Session events are global to the client session and may include:
|
||||||
|
|
||||||
|
- Server notifications
|
||||||
|
- Private messages
|
||||||
|
- User status updates
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Room Events
|
||||||
|
|
||||||
|
Room events are scoped to a specific room and are delivered only to clients
|
||||||
|
currently present in that room.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Game Events
|
||||||
|
|
||||||
|
Game events are scoped to a specific game and are delivered only to
|
||||||
|
participating clients.
|
||||||
|
|
||||||
|
Game events are grouped within a `GameEventContainer` to allow batching.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Event Batching
|
||||||
|
|
||||||
|
Some `ServerMessage` types may contain multiple logical events.
|
||||||
|
|
||||||
|
- `GameEventContainer` may batch multiple game events
|
||||||
|
- Other event types represent a single logical event
|
||||||
|
|
||||||
|
Clients must process all contained events **in order**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Error Semantics
|
||||||
|
|
||||||
|
Errors are communicated **exclusively** via `RESPONSE` messages.
|
||||||
|
|
||||||
|
Event messages are never used to signal command failure.
|
||||||
|
|
||||||
|
Common error responses include:
|
||||||
|
|
||||||
|
- `RespInvalidCommand`
|
||||||
|
- `RespLoginNeeded`
|
||||||
|
- `RespContextError`
|
||||||
|
- `RespChatFlood`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Related Concepts
|
||||||
|
|
||||||
|
- CommandContainer
|
||||||
|
- Client State Machine
|
||||||
|
- Response
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reference Proto Definition
|
||||||
|
|
||||||
|
```proto
|
||||||
|
message ServerMessage {
|
||||||
|
enum MessageType {
|
||||||
|
RESPONSE = 0;
|
||||||
|
SESSION_EVENT = 1;
|
||||||
|
GAME_EVENT_CONTAINER = 2;
|
||||||
|
ROOM_EVENT = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional MessageType message_type = 1;
|
||||||
|
optional Response response = 2;
|
||||||
|
optional SessionEvent session_event = 3;
|
||||||
|
optional GameEventContainer game_event_container = 4;
|
||||||
|
optional RoomEvent room_event = 5;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
@ -1,56 +1,197 @@
|
||||||
syntax = "proto2";
|
syntax = "proto2";
|
||||||
|
|
||||||
// Commands that are sent during a game to change the game state
|
/// Commands that are sent during a game to change the game state
|
||||||
message GameCommand {
|
message GameCommand {
|
||||||
|
|
||||||
|
/// Identifies the concrete game command to execute
|
||||||
enum GameCommandType {
|
enum GameCommandType {
|
||||||
|
|
||||||
|
/// Kick a player from the game.
|
||||||
|
/// Server: Server_Game::handleKickFromGame
|
||||||
|
/// Client: reflected via game state events
|
||||||
KICK_FROM_GAME = 1000;
|
KICK_FROM_GAME = 1000;
|
||||||
|
|
||||||
|
/// Leave the current game voluntarily.
|
||||||
|
/// Server: Server_Game::handleLeaveGame
|
||||||
|
/// Client: reflected via game state events
|
||||||
LEAVE_GAME = 1001;
|
LEAVE_GAME = 1001;
|
||||||
|
|
||||||
|
/// Send an in-game chat message.
|
||||||
|
/// Server: Server_Game::handleGameSay
|
||||||
|
/// Client: PlayerEventHandler::eventGameSay
|
||||||
GAME_SAY = 1002;
|
GAME_SAY = 1002;
|
||||||
|
|
||||||
|
/// Shuffle a zone (typically the library).
|
||||||
|
/// Server: Server_Game::handleShuffle
|
||||||
|
/// Client: PlayerEventHandler::eventShuffle
|
||||||
SHUFFLE = 1003;
|
SHUFFLE = 1003;
|
||||||
|
|
||||||
|
/// Take a mulligan at game start.
|
||||||
|
/// Server: Server_Game::handleMulligan
|
||||||
|
/// Client: reflected via game state events
|
||||||
MULLIGAN = 1004;
|
MULLIGAN = 1004;
|
||||||
|
|
||||||
|
/// Roll one or more dice.
|
||||||
|
/// Server: Server_Game::handleRollDie
|
||||||
|
/// Client: PlayerEventHandler::eventRollDie
|
||||||
ROLL_DIE = 1005;
|
ROLL_DIE = 1005;
|
||||||
|
|
||||||
|
/// Draw cards from the deck.
|
||||||
|
/// Server: Server_Game::handleDrawCards
|
||||||
|
/// Client: PlayerEventHandler::eventDrawCards
|
||||||
DRAW_CARDS = 1006;
|
DRAW_CARDS = 1006;
|
||||||
|
|
||||||
|
/// Undo a previous draw action.
|
||||||
|
/// Server: Server_Game::handleUndoDraw
|
||||||
|
/// Client: PlayerEventHandler::eventMoveCard (Context_UndoDraw)
|
||||||
UNDO_DRAW = 1007;
|
UNDO_DRAW = 1007;
|
||||||
|
|
||||||
|
/// Flip a card face up or face down.
|
||||||
|
/// Server: Server_Game::handleFlipCard
|
||||||
|
/// Client: PlayerEventHandler::eventFlipCard
|
||||||
FLIP_CARD = 1008;
|
FLIP_CARD = 1008;
|
||||||
|
|
||||||
|
/// Attach one card to another.
|
||||||
|
/// Server: Server_Game::handleAttachCard
|
||||||
|
/// Client: PlayerEventHandler::eventAttachCard
|
||||||
ATTACH_CARD = 1009;
|
ATTACH_CARD = 1009;
|
||||||
|
|
||||||
|
/// Create a token card.
|
||||||
|
/// Server: Server_Game::handleCreateToken
|
||||||
|
/// Client: PlayerEventHandler::eventCreateToken
|
||||||
CREATE_TOKEN = 1010;
|
CREATE_TOKEN = 1010;
|
||||||
|
|
||||||
|
/// Create a visual arrow between objects.
|
||||||
|
/// Server: Server_Game::handleCreateArrow
|
||||||
|
/// Client: PlayerEventHandler::eventCreateArrow
|
||||||
CREATE_ARROW = 1011;
|
CREATE_ARROW = 1011;
|
||||||
|
|
||||||
|
/// Delete a visual arrow.
|
||||||
|
/// Server: Server_Game::handleDeleteArrow
|
||||||
|
/// Client: PlayerEventHandler::eventDeleteArrow
|
||||||
DELETE_ARROW = 1012;
|
DELETE_ARROW = 1012;
|
||||||
|
|
||||||
|
/// Set a card attribute (e.g. tapped, flipped).
|
||||||
|
/// Server: Server_Game::handleSetCardAttr
|
||||||
|
/// Client: PlayerEventHandler::eventSetCardAttr
|
||||||
SET_CARD_ATTR = 1013;
|
SET_CARD_ATTR = 1013;
|
||||||
|
|
||||||
|
/// Set a counter value on a card.
|
||||||
|
/// Server: Server_Game::handleSetCardCounter
|
||||||
|
/// Client: PlayerEventHandler::eventSetCardCounter
|
||||||
SET_CARD_COUNTER = 1014;
|
SET_CARD_COUNTER = 1014;
|
||||||
|
|
||||||
|
/// Increment a counter on a card.
|
||||||
|
/// Server: Server_Game::handleIncCardCounter
|
||||||
|
/// Client: PlayerEventHandler::eventSetCardCounter
|
||||||
INC_CARD_COUNTER = 1015;
|
INC_CARD_COUNTER = 1015;
|
||||||
|
|
||||||
|
/// Mark the player as ready to start the game.
|
||||||
|
/// Server: Server_Game::handleReadyStart
|
||||||
|
/// Client: reflected via game state events
|
||||||
READY_START = 1016;
|
READY_START = 1016;
|
||||||
|
|
||||||
|
/// Concede the game.
|
||||||
|
/// Server: Server_Game::handleConcede
|
||||||
|
/// Client: reflected via game state events
|
||||||
CONCEDE = 1017;
|
CONCEDE = 1017;
|
||||||
|
|
||||||
|
/// Increment a global (non-card) counter.
|
||||||
|
/// Server: Server_Game::handleIncCounter
|
||||||
|
/// Client: PlayerEventHandler::eventSetCounter
|
||||||
INC_COUNTER = 1018;
|
INC_COUNTER = 1018;
|
||||||
|
|
||||||
|
/// Create a new global counter.
|
||||||
|
/// Server: Server_Game::handleCreateCounter
|
||||||
|
/// Client: PlayerEventHandler::eventCreateCounter
|
||||||
CREATE_COUNTER = 1019;
|
CREATE_COUNTER = 1019;
|
||||||
|
|
||||||
|
/// Set a global counter value.
|
||||||
|
/// Server: Server_Game::handleSetCounter
|
||||||
|
/// Client: PlayerEventHandler::eventSetCounter
|
||||||
SET_COUNTER = 1020;
|
SET_COUNTER = 1020;
|
||||||
|
|
||||||
|
/// Delete a global counter.
|
||||||
|
/// Server: Server_Game::handleDelCounter
|
||||||
|
/// Client: PlayerEventHandler::eventDelCounter
|
||||||
DEL_COUNTER = 1021;
|
DEL_COUNTER = 1021;
|
||||||
|
|
||||||
|
/// Advance to the next turn.
|
||||||
|
/// Server: Server_Game::handleNextTurn
|
||||||
|
/// Client: reflected via active player / phase events
|
||||||
NEXT_TURN = 1022;
|
NEXT_TURN = 1022;
|
||||||
|
|
||||||
|
/// Set the active phase of the turn.
|
||||||
|
/// Server: Server_Game::handleSetActivePhase
|
||||||
|
/// Client: reflected via game state events
|
||||||
SET_ACTIVE_PHASE = 1023;
|
SET_ACTIVE_PHASE = 1023;
|
||||||
|
|
||||||
|
/// Dump the contents of a zone.
|
||||||
|
/// Server: Server_Game::handleDumpZone
|
||||||
|
/// Client: PlayerEventHandler::eventDumpZone
|
||||||
DUMP_ZONE = 1024;
|
DUMP_ZONE = 1024;
|
||||||
// STOP_DUMP_ZONE = 1025; // obsolete
|
|
||||||
|
/// Reveal specific cards to players.
|
||||||
|
/// Server: Server_Game::handleRevealCards
|
||||||
|
/// Client: PlayerEventHandler::eventRevealCards
|
||||||
REVEAL_CARDS = 1026;
|
REVEAL_CARDS = 1026;
|
||||||
|
|
||||||
|
/// Move a card between zones.
|
||||||
|
/// Server: Server_Game::handleMoveCard
|
||||||
|
/// Client: PlayerEventHandler::eventMoveCard
|
||||||
MOVE_CARD = 1027;
|
MOVE_CARD = 1027;
|
||||||
|
|
||||||
|
/// Set the sideboard plan for the game.
|
||||||
|
/// Server: Server_Game::handleSetSideboardPlan
|
||||||
|
/// Client: not forwarded as a game event
|
||||||
SET_SIDEBOARD_PLAN = 1028;
|
SET_SIDEBOARD_PLAN = 1028;
|
||||||
|
|
||||||
|
/// Select a deck for the game.
|
||||||
|
/// Server: Server_Game::handleDeckSelect
|
||||||
|
/// Client: reflected via lobby / game state
|
||||||
DECK_SELECT = 1029;
|
DECK_SELECT = 1029;
|
||||||
|
|
||||||
|
/// Lock or unlock sideboarding.
|
||||||
|
/// Server: Server_Game::handleSetSideboardLock
|
||||||
|
/// Client: reflected via game state
|
||||||
SET_SIDEBOARD_LOCK = 1030;
|
SET_SIDEBOARD_LOCK = 1030;
|
||||||
|
|
||||||
|
/// Change zone properties (visibility, reveal-top, etc.).
|
||||||
|
/// Server: Server_Game::handleChangeZoneProperties
|
||||||
|
/// Client: PlayerEventHandler::eventChangeZoneProperties
|
||||||
CHANGE_ZONE_PROPERTIES = 1031;
|
CHANGE_ZONE_PROPERTIES = 1031;
|
||||||
|
|
||||||
|
/// Undo a previous concede.
|
||||||
|
/// Server: Server_Game::handleUnconcede
|
||||||
|
/// Client: reflected via game state
|
||||||
UNCONCEDE = 1032;
|
UNCONCEDE = 1032;
|
||||||
|
|
||||||
|
/// Execute a command on behalf of another player.
|
||||||
|
/// Server: Server_Game::handleJudge
|
||||||
|
/// Client: transparent (wrapped commands handled normally)
|
||||||
JUDGE = 1033;
|
JUDGE = 1033;
|
||||||
|
|
||||||
|
/// Reverse the current turn order.
|
||||||
|
/// Server: Server_Game::handleReverseTurn
|
||||||
|
/// Client: reflected via subsequent turn events
|
||||||
REVERSE_TURN = 1034;
|
REVERSE_TURN = 1034;
|
||||||
}
|
}
|
||||||
|
|
||||||
extensions 100 to max;
|
extensions 100 to max;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A wrapper around a normal game command that allows a privileged user to send a command on behalf of another player
|
/// A wrapper around a normal game command that allows a privileged user
|
||||||
|
/// to send a command on behalf of another player.
|
||||||
message Command_Judge {
|
message Command_Judge {
|
||||||
|
|
||||||
extend GameCommand {
|
extend GameCommand {
|
||||||
|
/// Judge command extension payload
|
||||||
optional Command_Judge ext = 1033;
|
optional Command_Judge ext = 1033;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The player on whose behalf this command is sent
|
/// The player on whose behalf this command is sent.
|
||||||
optional sint32 target_id = 1 [default = -1];
|
optional sint32 target_id = 1 [default = -1];
|
||||||
|
|
||||||
// The wrapped game command
|
/// One or more wrapped game commands to execute.
|
||||||
repeated GameCommand game_command = 2;
|
repeated GameCommand game_command = 2;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,44 @@
|
||||||
syntax = "proto2";
|
syntax = "proto2";
|
||||||
|
|
||||||
// Sent immediately after a command with the same cmd_id, connecting it to the command sent to the server
|
/// Server response envelope linking to a command
|
||||||
|
/**
|
||||||
|
* This message is sent immediately after a client command, using the same `cmd_id`
|
||||||
|
* to connect the response to the command.
|
||||||
|
*
|
||||||
|
* Responses may contain standard outcome codes (`ResponseCode`) and indicate
|
||||||
|
* what type of response the server is sending (`ResponseType`).
|
||||||
|
*/
|
||||||
message Response {
|
message Response {
|
||||||
|
|
||||||
|
// Outcome of the command sent by the client
|
||||||
enum ResponseCode {
|
enum ResponseCode {
|
||||||
RespNotConnected = -1;
|
RespNotConnected = -1; // Client is not connected or session expired
|
||||||
RespNothing = 0;
|
RespNothing = 0; // No response required
|
||||||
RespOk = 1;
|
RespOk = 1; // Command succeeded
|
||||||
RespNotInRoom = 2;
|
RespNotInRoom = 2; // Client is not in the room for this command
|
||||||
RespInternalError = 3;
|
RespInternalError = 3; // Server encountered an unexpected error
|
||||||
RespInvalidCommand = 4;
|
RespInvalidCommand = 4; // Command was invalid or unrecognized
|
||||||
RespInvalidData = 5;
|
RespInvalidData = 5; // Command data was invalid or malformed
|
||||||
RespNameNotFound = 6;
|
RespNameNotFound = 6; // Target user not found
|
||||||
RespLoginNeeded = 7;
|
RespLoginNeeded = 7; // Client must log in first
|
||||||
RespFunctionNotAllowed = 8;
|
RespFunctionNotAllowed = 8; // Client tried to perform a restricted action
|
||||||
RespGameNotStarted = 9;
|
RespGameNotStarted = 9; // Game has not started yet
|
||||||
RespGameFull = 10;
|
RespGameFull = 10; // Game is full
|
||||||
RespContextError = 11;
|
RespContextError = 11; // Context (room/game) mismatch
|
||||||
RespWrongPassword = 12;
|
RespWrongPassword = 12; // Password for this room or game is incorrect
|
||||||
RespSpectatorsNotAllowed = 13;
|
RespSpectatorsNotAllowed = 13; // Spectators are not allowed in this room/game
|
||||||
RespOnlyBuddies = 14;
|
RespOnlyBuddies = 14; // Only buddies can perform this action
|
||||||
RespUserLevelTooLow = 15;
|
RespUserLevelTooLow = 15; // User’s permission level is insufficient
|
||||||
RespInIgnoreList = 16;
|
RespInIgnoreList = 16; // Target user has ignored the client
|
||||||
RespWouldOverwriteOldSession = 17;
|
RespWouldOverwriteOldSession = 17; // Would overwrite an existing session
|
||||||
RespChatFlood = 18;
|
RespChatFlood = 18; // Too many messages sent in short time
|
||||||
RespUserIsBanned = 19;
|
RespUserIsBanned = 19; // Client is banned
|
||||||
RespAccessDenied = 20;
|
RespAccessDenied = 20; // Access to this action is denied
|
||||||
RespUsernameInvalid = 21;
|
RespUsernameInvalid = 21; // Username is invalid
|
||||||
RespRegistrationRequired = 22;
|
RespRegistrationRequired = 22; // Registration is required
|
||||||
RespRegistrationAccepted = 23; // Server agrees to process client's registration request
|
RespRegistrationAccepted = 23; // Server agrees to process client's registration request
|
||||||
RespUserAlreadyExists = 24; // Client attempted to register a name which is already registered
|
RespUserAlreadyExists = 24; // Client attempted to register a name which is already registered
|
||||||
RespEmailRequiredToRegister = 25; // Server requires email to register accounts but client did not provide one
|
RespEmailRequiredToRegister = 25; // Server requires email to register accounts but client did not provide one
|
||||||
RespTooManyRequests = 26; // Server refused to complete command because client has sent too many too quickly
|
RespTooManyRequests = 26; // Server refused to complete command because client has sent too many too quickly
|
||||||
RespPasswordTooShort = 27; // Server requires a decent password
|
RespPasswordTooShort = 27; // Server requires a decent password
|
||||||
RespAccountNotActivated =
|
RespAccountNotActivated =
|
||||||
|
|
@ -45,33 +54,36 @@ message Response {
|
||||||
RespServerFull = 36; // Server user limit reached
|
RespServerFull = 36; // Server user limit reached
|
||||||
RespEmailBlackListed = 37; // Server has blocked the email address provided for registration for some reason
|
RespEmailBlackListed = 37; // Server has blocked the email address provided for registration for some reason
|
||||||
}
|
}
|
||||||
enum ResponseType {
|
|
||||||
JOIN_ROOM = 1000;
|
|
||||||
LIST_USERS = 1001;
|
|
||||||
GET_GAMES_OF_USER = 1002;
|
|
||||||
GET_USER_INFO = 1003;
|
|
||||||
DUMP_ZONE = 1004;
|
|
||||||
LOGIN = 1005;
|
|
||||||
DECK_LIST = 1006;
|
|
||||||
DECK_DOWNLOAD = 1007;
|
|
||||||
DECK_UPLOAD = 1008;
|
|
||||||
REGISTER = 1009;
|
|
||||||
ACTIVATE = 1010;
|
|
||||||
ADJUST_MOD = 1011;
|
|
||||||
BAN_HISTORY = 1012;
|
|
||||||
WARN_HISTORY = 1013;
|
|
||||||
WARN_LIST = 1014;
|
|
||||||
VIEW_LOG = 1015;
|
|
||||||
FORGOT_PASSWORD_REQUEST = 1016;
|
|
||||||
PASSWORD_SALT = 1017;
|
|
||||||
GET_ADMIN_NOTES = 1018;
|
|
||||||
REPLAY_LIST = 1100;
|
|
||||||
REPLAY_DOWNLOAD = 1101;
|
|
||||||
REPLAY_GET_CODE = 1102;
|
|
||||||
CARD_ART_RULE_LIST = 1200;
|
|
||||||
}
|
|
||||||
required uint64 cmd_id = 1;
|
|
||||||
optional ResponseCode response_code = 2;
|
|
||||||
|
|
||||||
extensions 100 to max;
|
// Type of response, used to route handling on the client
|
||||||
|
enum ResponseType {
|
||||||
|
JOIN_ROOM = 1000; // Response for joining a room
|
||||||
|
LIST_USERS = 1001; // Response listing users
|
||||||
|
GET_GAMES_OF_USER = 1002; // Response with user's games
|
||||||
|
GET_USER_INFO = 1003; // Response with user info
|
||||||
|
DUMP_ZONE = 1004; // Response with zone dump
|
||||||
|
LOGIN = 1005; // Response to login attempt
|
||||||
|
DECK_LIST = 1006; // Response with deck list
|
||||||
|
DECK_DOWNLOAD = 1007; // Response for deck download
|
||||||
|
DECK_UPLOAD = 1008; // Response for deck upload
|
||||||
|
REGISTER = 1009; // Response to registration
|
||||||
|
ACTIVATE = 1010; // Response to activation
|
||||||
|
ADJUST_MOD = 1011; // Response to mod adjustments
|
||||||
|
BAN_HISTORY = 1012; // Response with ban history
|
||||||
|
WARN_HISTORY = 1013; // Response with warn history
|
||||||
|
WARN_LIST = 1014; // Response with current warnings
|
||||||
|
VIEW_LOG = 1015; // Response with logs
|
||||||
|
FORGOT_PASSWORD_REQUEST = 1016; // Response to password reset request
|
||||||
|
PASSWORD_SALT = 1017; // Response containing password salt
|
||||||
|
GET_ADMIN_NOTES = 1018; // Response with admin notes
|
||||||
|
REPLAY_LIST = 1100; // Response listing replays
|
||||||
|
REPLAY_DOWNLOAD = 1101; // Response for replay download
|
||||||
|
REPLAY_GET_CODE = 1102; // Response containing replay code
|
||||||
|
CARD_ART_RULE_LIST = 1200; // Response containing a list of card art rules
|
||||||
|
}
|
||||||
|
|
||||||
|
required uint64 cmd_id = 1; // Command ID that this response corresponds to
|
||||||
|
optional ResponseCode response_code = 2; // Outcome code of the command
|
||||||
|
|
||||||
|
extensions 100 to max; // Protobuf extensions reserved for future use
|
||||||
}
|
}
|
||||||
|
|
|
||||||
285
proto2cpp.py
Normal file
285
proto2cpp.py
Normal file
|
|
@ -0,0 +1,285 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
##
|
||||||
|
# Doxygen filter for Google Protocol Buffers .proto files.
|
||||||
|
# This script converts .proto files into C++ style ones
|
||||||
|
# and prints the output to standard output.
|
||||||
|
#
|
||||||
|
# version 0.8-beta OSI
|
||||||
|
#
|
||||||
|
# How to enable this filter in Doxygen:
|
||||||
|
# 1. Generate Doxygen configuration file with command 'doxygen -g <filename>'
|
||||||
|
# e.g. doxygen -g doxyfile
|
||||||
|
# 2. In the Doxygen configuration file, find FILE_PATTERNS and add *.proto
|
||||||
|
# FILE_PATTERNS = *.proto
|
||||||
|
# 3. In the Doxygen configuration file, find EXTENSION_MAPPING and add proto=C++
|
||||||
|
# EXTENSION_MAPPING = proto=C++
|
||||||
|
# 4. In the Doxygen configuration file, find INPUT_FILTER and add this script
|
||||||
|
# INPUT_FILTER = "python proto2cpp.py"
|
||||||
|
# 5. Run Doxygen with the modified configuration
|
||||||
|
# doxygen doxyfile
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Version 0.8 2018 Bugfix regarding long comments, remove typo
|
||||||
|
# Version 0.7 2018 Bugfix and extensions have been made by Open Simulation Interface (OSI) Carsten Kuebler https://github.com/OpenSimulationInterface,
|
||||||
|
# Copyright (C) 2016 Regents of the University of California https://github.com/vgteam/vg
|
||||||
|
# Copyright (C) 2012-2015 Timo Marjoniemi https://sourceforge.net/p/proto2cpp/wiki/Home/
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# This library is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2.1 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This library is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
##
|
||||||
|
|
||||||
|
import fnmatch
|
||||||
|
import inspect
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
## Class for converting Google Protocol Buffers .proto files into C++ style output to enable Doxygen usage.
|
||||||
|
##
|
||||||
|
## The C++ style output is printed into standard output.<br />
|
||||||
|
## There are three different logging levels for the class:
|
||||||
|
## <ul><li>#logNone: do not log anything</li>
|
||||||
|
## <li>#logErrors: log errors only</li>
|
||||||
|
## <li>#logAll: log everything</li></ul>
|
||||||
|
## Logging level is determined by \c #logLevel.<br />
|
||||||
|
## Error logs are written to file determined by \c #errorLogFile.<br />
|
||||||
|
## Debug logs are written to file determined by \c #logFile.
|
||||||
|
#
|
||||||
|
class proto2cpp:
|
||||||
|
|
||||||
|
## Logging level: do not log anything.
|
||||||
|
logNone = 0
|
||||||
|
## Logging level: log errors only.
|
||||||
|
logErrors = 1
|
||||||
|
## Logging level: log everything.
|
||||||
|
logAll = 2
|
||||||
|
|
||||||
|
## Constructor
|
||||||
|
#
|
||||||
|
def __init__(self):
|
||||||
|
## Debug log file name.
|
||||||
|
self.logFile = "proto2cpp.log"
|
||||||
|
## Error log file name.
|
||||||
|
self.errorLogFile = "proto2cpp.error.log"
|
||||||
|
## Logging level.
|
||||||
|
self.logLevel = self.logNone
|
||||||
|
|
||||||
|
## Handles a file.
|
||||||
|
##
|
||||||
|
## If @p fileName has .proto suffix, it is processed through parseFile().
|
||||||
|
## Otherwise it is printed to stdout as is except for file \c proto2cpp.py without
|
||||||
|
## path since it's the script given to python for processing.
|
||||||
|
##
|
||||||
|
## @param fileName Name of the file to be handled.
|
||||||
|
#
|
||||||
|
def handleFile(self, fileName):
|
||||||
|
if fnmatch.fnmatch(filename, '*.proto'):
|
||||||
|
self.log('\nXXXXXXXXXX\nXX ' + filename + '\nXXXXXXXXXX\n\n')
|
||||||
|
# Open the file. Use try to detect whether or not we have an actual file.
|
||||||
|
if (sys.version_info >= (3, 0)):
|
||||||
|
try:
|
||||||
|
with open(filename, 'r', encoding='utf8') as inputFile:
|
||||||
|
self.parseFile(inputFile)
|
||||||
|
pass
|
||||||
|
except IOError as e:
|
||||||
|
self.logError('the file ' + filename + ' could not be opened for reading')
|
||||||
|
else:
|
||||||
|
# Python 2 code in this block
|
||||||
|
try:
|
||||||
|
with open(filename, 'r') as inputFile:
|
||||||
|
self.parseFile(inputFile)
|
||||||
|
pass
|
||||||
|
except IOError as e:
|
||||||
|
self.logError('the file ' + filename + ' could not be opened for reading')
|
||||||
|
|
||||||
|
elif not fnmatch.fnmatch(filename, os.path.basename(inspect.getfile(inspect.currentframe()))):
|
||||||
|
self.log('\nXXXXXXXXXX\nXX ' + filename + '\nXXXXXXXXXX\n\n')
|
||||||
|
if (sys.version_info > (3, 0)):
|
||||||
|
try:
|
||||||
|
with open(filename, 'r', encoding='utf8') as theFile:
|
||||||
|
output = ''
|
||||||
|
for theLine in theFile:
|
||||||
|
output += theLine
|
||||||
|
print(output)
|
||||||
|
self.log(output)
|
||||||
|
pass
|
||||||
|
except IOError as e:
|
||||||
|
self.logError('the file ' + filename + ' could not be opened for reading')
|
||||||
|
else:
|
||||||
|
# Python 2 code in this block
|
||||||
|
try:
|
||||||
|
with open(filename, 'r') as theFile:
|
||||||
|
output = ''
|
||||||
|
for theLine in theFile:
|
||||||
|
output += theLine
|
||||||
|
print(output)
|
||||||
|
self.log(output)
|
||||||
|
pass
|
||||||
|
except IOError as e:
|
||||||
|
self.logError('the file ' + filename + ' could not be opened for reading')
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.log('\nXXXXXXXXXX\nXX ' + filename + ' --skipped--\nXXXXXXXXXX\n\n')
|
||||||
|
|
||||||
|
## Parser function.
|
||||||
|
##
|
||||||
|
## The function takes a .proto file object as input
|
||||||
|
## parameter and modifies the contents into C++ style.
|
||||||
|
## The modified data is printed into standard output.
|
||||||
|
##
|
||||||
|
## @param inputFile Input file object
|
||||||
|
#
|
||||||
|
def parseFile(self, inputFile):
|
||||||
|
# Go through the input file line by line.
|
||||||
|
isEnum = False
|
||||||
|
isPackage = False
|
||||||
|
isMultilineComment = False
|
||||||
|
# This variable is here as a workaround for not getting extra line breaks (each line
|
||||||
|
# ends with a line separator and print() method will add another one).
|
||||||
|
# We will be adding lines into this var and then print the var out at the end.
|
||||||
|
theOutput = ''
|
||||||
|
for line in inputFile:
|
||||||
|
# Search for comment ("//") and add one more slash character ("/") to the comment
|
||||||
|
# block to make Doxygen detect it.
|
||||||
|
matchComment = re.search("//", line)
|
||||||
|
# Search for semicolon and if one is found before comment, add a third slash character
|
||||||
|
# ("/") and a smaller than ("<") character to the comment to make Doxygen detect it.
|
||||||
|
matchSemicolon = re.search(";", line)
|
||||||
|
if matchSemicolon is not None and (matchComment is not None and matchSemicolon.start() < matchComment.start()):
|
||||||
|
comment = "///<" + line[matchComment.end():]
|
||||||
|
# Replace '.' in nested message references with '::'
|
||||||
|
# don't work for multi-nested references and generates problems with URLs and acronyms
|
||||||
|
#comment = re.sub(r'\s(\w+)\.(\w+)\s', r' \1::\2 ', comment)
|
||||||
|
line = line[:matchComment.start()]
|
||||||
|
elif matchComment is not None:
|
||||||
|
if isMultilineComment:
|
||||||
|
comment = " * " + line[matchComment.end():]
|
||||||
|
else:
|
||||||
|
comment = "/** " + line[matchComment.end():]
|
||||||
|
isMultilineComment = True
|
||||||
|
# replace '.' in nested message references with '::'
|
||||||
|
# don't work for multi-nested references and generates problems with URLs and acronyms
|
||||||
|
#comment = re.sub(r'\s(\w+)\.(\w+)\s', r' \1::\2 ', comment)
|
||||||
|
line = line[:matchComment.start()]
|
||||||
|
else:
|
||||||
|
comment = ""
|
||||||
|
|
||||||
|
# End multiline comment, if there is no comment or if there are some chars before the comment.
|
||||||
|
if (matchComment is None or len(line.strip())>0) and isMultilineComment:
|
||||||
|
theOutput += " */\n"
|
||||||
|
isMultilineComment = False
|
||||||
|
|
||||||
|
# line = line.replace(".", "::") but not in quoted strings (Necessary for import statement)
|
||||||
|
line = re.sub(r'\.(?=(?:[^"]*"[^"]*")*[^"]*$)',r'::',line)
|
||||||
|
|
||||||
|
# Search for " option ...;", remove it
|
||||||
|
line = re.sub(r'\boption\b[^;]+;', r'', line)
|
||||||
|
|
||||||
|
# Search for " package ", make a namespace
|
||||||
|
matchPackage = re.search(r"\bpackage\b", line)
|
||||||
|
if matchPackage is not None:
|
||||||
|
isPackage = True
|
||||||
|
# Convert to C++-style separator and block instead of statement
|
||||||
|
line = "namespace" + line[:matchPackage.start()] + line[matchPackage.end():].replace(";", " {")
|
||||||
|
|
||||||
|
# Search for " repeated " fields and make them ...
|
||||||
|
#matchRepeated = re.search(r"\brepeated\b", line)
|
||||||
|
#if matchRepeated is not None:
|
||||||
|
# # Convert
|
||||||
|
# line = re.sub(r'\brepeated\s+(\S+)', r' repeated \1', line)
|
||||||
|
|
||||||
|
# Search for "enum", start changing all semicolons (";") to commas (",").
|
||||||
|
matchEnum = re.search(r"\benum\b", line)
|
||||||
|
if matchEnum is not None:
|
||||||
|
isEnum = True
|
||||||
|
|
||||||
|
# Search semicolon if we have detected an enum, and replace semicolon with comma.
|
||||||
|
if isEnum is True and matchSemicolon is not None:
|
||||||
|
line = line.replace(";", ",")
|
||||||
|
|
||||||
|
# Search for a closing brace.
|
||||||
|
matchClosingBrace = re.search("}", line)
|
||||||
|
if isEnum is True and matchClosingBrace is not None:
|
||||||
|
line = line[:matchClosingBrace.start()] + "};" + line[matchClosingBrace.end():]
|
||||||
|
isEnum = False
|
||||||
|
elif isEnum is False and matchClosingBrace is not None:
|
||||||
|
# Message (to be struct) ends => add semicolon so that it'll
|
||||||
|
# be a proper C(++) struct and Doxygen will handle it correctly.
|
||||||
|
line = line[:matchClosingBrace.start()] + "};" + line[matchClosingBrace.end():]
|
||||||
|
|
||||||
|
# Replacements change start of comment...
|
||||||
|
matchMsg = re.search(r"\bmessage\b", line)
|
||||||
|
if matchMsg is not None:
|
||||||
|
line = line[:matchMsg.start()] + "struct" + line[matchMsg.end():]
|
||||||
|
|
||||||
|
# Replacements change start of comment...
|
||||||
|
matchExt = re.search(r"\bextend\b", line)
|
||||||
|
if matchExt is not None:
|
||||||
|
a_extend = line[matchExt.end():]
|
||||||
|
matchName = re.search(r"\b\w[\S:]*\b", a_extend)
|
||||||
|
if matchName is not None:
|
||||||
|
name = a_extend[matchName.start():matchName.end()]
|
||||||
|
name = re.sub(r'\w+::',r'',name)
|
||||||
|
a_extend = a_extend[:matchName.start()] + name + ": public " + a_extend[matchName.start():]
|
||||||
|
else:
|
||||||
|
a_extend = "_Dummy: public " + a_extend;
|
||||||
|
line = line[:matchExt.start()] + "struct " + a_extend
|
||||||
|
|
||||||
|
theOutput += (line.strip() + ' ' + comment.strip()).strip() + '\n'
|
||||||
|
|
||||||
|
if isPackage:
|
||||||
|
# Close the package namespace
|
||||||
|
theOutput += "}"
|
||||||
|
isPackage = False
|
||||||
|
|
||||||
|
# Now that we've got all lines in the string let's split the lines and print out
|
||||||
|
# one by one.
|
||||||
|
# This is a workaround to get rid of extra empty line at the end which print() method adds.
|
||||||
|
lines = theOutput.splitlines()
|
||||||
|
for line in lines:
|
||||||
|
if len(line) > 0:
|
||||||
|
print(line) # Add linebreak to generate documentation correct.
|
||||||
|
self.log(line + '\n')
|
||||||
|
|
||||||
|
## Writes @p string to log file.
|
||||||
|
##
|
||||||
|
## #logLevel must be #logAll or otherwise the logging is skipped.
|
||||||
|
##
|
||||||
|
## @param string String to be written to log file.
|
||||||
|
#
|
||||||
|
def log(self, string):
|
||||||
|
if self.logLevel >= self.logAll:
|
||||||
|
with open(self.logFile, 'a') as theFile:
|
||||||
|
theFile.write(string)
|
||||||
|
|
||||||
|
## Writes @p string to error log file.
|
||||||
|
##
|
||||||
|
## #logLevel must be #logError or #logAll or otherwise the logging is skipped.
|
||||||
|
##
|
||||||
|
## @param string String to be written to error log file.
|
||||||
|
#
|
||||||
|
def logError(self, string):
|
||||||
|
if self.logLevel >= self.logError:
|
||||||
|
with open(self.errorLogFile, 'a') as theFile:
|
||||||
|
theFile.write(string)
|
||||||
|
|
||||||
|
converter = proto2cpp()
|
||||||
|
# Doxygen will give us the file names
|
||||||
|
for filename in sys.argv[1:]:
|
||||||
|
converter.handleFile(filename)
|
||||||
|
|
||||||
|
# end of file
|
||||||
Loading…
Add table
Add a link
Reference in a new issue