mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-04-27 07:48:01 -07:00
Merge ssh://cockatrice.git.sourceforge.net/gitroot/cockatrice
This commit is contained in:
commit
7023b95db0
19 changed files with 157 additions and 36 deletions
110
cockatrice/doc/protocol.txt
Normal file
110
cockatrice/doc/protocol.txt
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
1. Abstract
|
||||
|
||||
The Cockatrice protocol is a client/server protocol intended for communication between
|
||||
a card game client and a suitable server. It is designed with the goal in mind to make
|
||||
playing card games, such as Magic the Gathering, over a network easy while eliminating
|
||||
the possibility of unfair play. Because of that, the server stores all hidden information
|
||||
and transmits pieces of it to clients only when necessary.
|
||||
|
||||
2. Protocol structure
|
||||
|
||||
All communication is done over a TCP/IP connection. The protocol is text based.
|
||||
Strings are encoded in UTF-8 and have UNIX-style line endings (\n).
|
||||
|
||||
There are four distinct types of messages:
|
||||
- Command (section 3)
|
||||
- Response (section 4)
|
||||
- Event (section 5)
|
||||
- List (section 6)
|
||||
|
||||
3. Commands
|
||||
|
||||
A command can only be sent from client to server and has the following structure:
|
||||
{ID}|{command}|{parameter1}|{parameter2}...
|
||||
"ID" is an arbitrary number to be chosen uniquely for each command.
|
||||
"command" is a command identifier (see section 3).
|
||||
It depends on the command identifier what has to be passed as parameters.
|
||||
|
||||
3.1 ping
|
||||
|
||||
Flags:
|
||||
none
|
||||
Parameters:
|
||||
none
|
||||
Valid response codes:
|
||||
ok
|
||||
|
||||
No effect.
|
||||
|
||||
3.2 login
|
||||
|
||||
Flags:
|
||||
none
|
||||
Parameters:
|
||||
User name (string)
|
||||
Password (string)
|
||||
Valid response codes:
|
||||
ok
|
||||
password
|
||||
|
||||
If the supplied credentials are correct, "ok" is returned and the connection state
|
||||
is set to authenticated. (The server is not required to actually check the validity
|
||||
of the credentials.)
|
||||
Otherwise, "password" is returned.
|
||||
|
||||
3.3 list_games
|
||||
|
||||
Flags:
|
||||
login needed
|
||||
Parameters:
|
||||
none
|
||||
Valid response codes:
|
||||
ok
|
||||
|
||||
If the connection state is unauthenticated, "login_needed" is returned.
|
||||
Otherwise, "ok" is returned and for each game currently, a list_games event XXX is
|
||||
sent to the client. The "accepts game list changes" flag of the connection is set.
|
||||
|
||||
3.4 create_game
|
||||
3.5 join_game
|
||||
3.6 leave_game
|
||||
3.7 list_players
|
||||
3.8 say
|
||||
3.9 submit_deck
|
||||
3.10 ready_start
|
||||
3.11 shuffle
|
||||
3.12 draw_cards
|
||||
3.13 reveal_card
|
||||
3.14 move_card
|
||||
3.15 create_token
|
||||
3.16 set_card_attr
|
||||
3.17 inc_counter
|
||||
3.18 add_counter
|
||||
3.19 set_counter
|
||||
3.20 del_counter
|
||||
3.21 list_counters
|
||||
3.22 list_zones
|
||||
3.23 dump_zone
|
||||
3.24 roll_dice
|
||||
3.25 set_active_player
|
||||
3.26 set_active_phase
|
||||
|
||||
4. Responses
|
||||
|
||||
After processing any command, the server sends a response to the client, indicating
|
||||
whether the command was understood and valid.
|
||||
A response can only be sent from server to client and has the following structure:
|
||||
resp|{ID}|{resp-code}
|
||||
|
||||
{ID} is the identifier belonging to the command in question.
|
||||
{resp-code} contains information about the processing of the command. It can have the
|
||||
following values:
|
||||
ok (Success)
|
||||
login_needed (Error: Command requires login)
|
||||
syntax (Error: Invalid command or parameters)
|
||||
context (Error: Command cannot be applied here)
|
||||
password (Error: Wrong login data)
|
||||
|
||||
The response code "syntax" is valid as a response to any command and is
|
||||
hence not explicitly listed in section 3. The response code "login_needed" applies
|
||||
to all commands with the "login needed" flag.
|
||||
|
|
@ -70,7 +70,7 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
|||
void CardItem::setName(const QString &_name)
|
||||
{
|
||||
name = _name;
|
||||
update(boundingRect());
|
||||
update();
|
||||
}
|
||||
|
||||
void CardItem::setTapped(bool _tapped)
|
||||
|
|
@ -80,31 +80,31 @@ void CardItem::setTapped(bool _tapped)
|
|||
setTransform(QTransform().translate((float) CARD_WIDTH / 2, (float) CARD_HEIGHT / 2).rotate(90).translate((float) -CARD_WIDTH / 2, (float) -CARD_HEIGHT / 2));
|
||||
else
|
||||
setTransform(QTransform());
|
||||
update(boundingRect());
|
||||
update();
|
||||
}
|
||||
|
||||
void CardItem::setAttacking(bool _attacking)
|
||||
{
|
||||
attacking = _attacking;
|
||||
update(boundingRect());
|
||||
update();
|
||||
}
|
||||
|
||||
void CardItem::setFaceDown(bool _facedown)
|
||||
{
|
||||
facedown = _facedown;
|
||||
update(boundingRect());
|
||||
update();
|
||||
}
|
||||
|
||||
void CardItem::setCounters(int _counters)
|
||||
{
|
||||
counters = _counters;
|
||||
update(boundingRect());
|
||||
update();
|
||||
}
|
||||
|
||||
void CardItem::setAnnotation(const QString &_annotation)
|
||||
{
|
||||
annotation = _annotation;
|
||||
update(boundingRect());
|
||||
update();
|
||||
}
|
||||
|
||||
void CardItem::setDoesntUntap(bool _doesntUntap)
|
||||
|
|
@ -120,7 +120,7 @@ void CardItem::resetState()
|
|||
annotation = QString();
|
||||
setTapped(false);
|
||||
setDoesntUntap(false);
|
||||
update(boundingRect());
|
||||
update();
|
||||
}
|
||||
|
||||
CardDragItem *CardItem::createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool faceDown)
|
||||
|
|
@ -215,7 +215,7 @@ QVariant CardItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QV
|
|||
return value;
|
||||
} else if (change == ItemSelectedHasChanged) {
|
||||
qDebug("selection changed");
|
||||
update(boundingRect());
|
||||
update();
|
||||
return value;
|
||||
} else
|
||||
return QGraphicsItem::itemChange(change, value);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "cardlist.h"
|
||||
#include "carditem.h"
|
||||
|
||||
CardList::CardList(bool _contentsKnown)
|
||||
: QList<CardItem *>(), contentsKnown(_contentsKnown)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
#ifndef CARDLIST_H
|
||||
#define CARDLIST_H
|
||||
|
||||
#include "carditem.h"
|
||||
#include <QList>
|
||||
|
||||
class CardItem;
|
||||
|
||||
class CardList : public QList<CardItem *> {
|
||||
protected:
|
||||
bool contentsKnown;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
#include "zoneviewzone.h"
|
||||
|
||||
CardZone::CardZone(Player *_p, const QString &_name, bool _hasCardAttr, bool _isShufflable, QGraphicsItem *parent, bool isView)
|
||||
: AbstractGraphicsItem(parent), player(_p), name(_name), cards(NULL), view(NULL), menu(NULL), hasCardAttr(_hasCardAttr), isShufflable(_isShufflable)
|
||||
: AbstractGraphicsItem(parent), player(_p), name(_name), cards(NULL), view(NULL), menu(NULL), doubleClickAction(0), hasCardAttr(_hasCardAttr), isShufflable(_isShufflable)
|
||||
{
|
||||
if (!isView)
|
||||
player->addZone(this);
|
||||
|
|
@ -27,7 +27,7 @@ void CardZone::clearContents()
|
|||
cards->clear();
|
||||
}
|
||||
|
||||
void CardZone::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
||||
void CardZone::mouseDoubleClickEvent(QGraphicsSceneMouseEvent */*event*/)
|
||||
{
|
||||
if (doubleClickAction)
|
||||
doubleClickAction->trigger();
|
||||
|
|
@ -71,8 +71,7 @@ CardItem *CardZone::getCard(int cardId, const QString &cardName)
|
|||
|
||||
CardItem *CardZone::takeCard(int position, int cardId, const QString &cardName)
|
||||
{
|
||||
if (position >= cards->size())
|
||||
return NULL;
|
||||
Q_ASSERT(position < cards->size());
|
||||
|
||||
CardItem *c = cards->takeAt(position);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <QString>
|
||||
#include "cardlist.h"
|
||||
#include "carditem.h"
|
||||
#include "abstractgraphicsitem.h"
|
||||
|
||||
class Player;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ void Counter::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*
|
|||
void Counter::setValue(int _value)
|
||||
{
|
||||
value = _value;
|
||||
update(boundingRect());
|
||||
update();
|
||||
}
|
||||
|
||||
void Counter::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ void Game::initSayMenu()
|
|||
|
||||
Player *Game::addPlayer(int playerId, const QString &playerName, QPointF base, bool local)
|
||||
{
|
||||
Player *newPlayer = new Player(playerName, playerId, base, local, db, client, scene);
|
||||
Player *newPlayer = new Player(playerName, playerId, base, local, db, client, scene, this);
|
||||
|
||||
connect(newPlayer, SIGNAL(hoverCard(QString)), this, SIGNAL(hoverCard(QString)));
|
||||
connect(newPlayer, SIGNAL(sigShowCardMenu(QPoint)), this, SLOT(showCardMenu(QPoint)));
|
||||
|
|
@ -346,7 +346,8 @@ void Game::actTap()
|
|||
QListIterator<QGraphicsItem *> i(scene->selectedItems());
|
||||
while (i.hasNext()) {
|
||||
CardItem *temp = (CardItem *) i.next();
|
||||
client->setCardAttr(qgraphicsitem_cast<CardZone *>(temp->parentItem())->getName(), temp->getId(), "tapped", "1");
|
||||
if (!temp->getTapped())
|
||||
client->setCardAttr(qgraphicsitem_cast<CardZone *>(temp->parentItem())->getName(), temp->getId(), "tapped", "1");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -355,7 +356,8 @@ void Game::actUntap()
|
|||
QListIterator<QGraphicsItem *> i(scene->selectedItems());
|
||||
while (i.hasNext()) {
|
||||
CardItem *temp = (CardItem *) i.next();
|
||||
client->setCardAttr(qgraphicsitem_cast<CardZone *>(temp->parentItem())->getName(), temp->getId(), "tapped", "0");
|
||||
if (temp->getTapped())
|
||||
client->setCardAttr(qgraphicsitem_cast<CardZone *>(temp->parentItem())->getName(), temp->getId(), "tapped", "0");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@ private slots:
|
|||
void actEditMessages();
|
||||
|
||||
void showCardMenu(QPoint p);
|
||||
void actTap();
|
||||
void actUntap();
|
||||
void actDoesntUntap();
|
||||
void actFlip();
|
||||
void actAddCounter();
|
||||
|
|
@ -54,6 +52,9 @@ private slots:
|
|||
void gameEvent(const ServerEventData &msg);
|
||||
void playerListReceived(QList<ServerPlayer *> playerList);
|
||||
void readyStart();
|
||||
public slots:
|
||||
void actTap();
|
||||
void actUntap();
|
||||
signals:
|
||||
void submitDecklist();
|
||||
void hoverCard(QString name);
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ void HandZone::addCardImpl(CardItem *card, int x, int /*y*/)
|
|||
card->setParentItem(this);
|
||||
card->resetState();
|
||||
card->setVisible(true);
|
||||
card->update(card->boundingRect());
|
||||
card->update();
|
||||
}
|
||||
|
||||
void HandZone::handleDropEvent(int cardId, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/)
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ void LibraryZone::handleDropEvent(int cardId, CardZone *startZone, const QPoint
|
|||
|
||||
void LibraryZone::reorganizeCards()
|
||||
{
|
||||
update(boundingRect());
|
||||
update();
|
||||
}
|
||||
|
||||
void LibraryZone::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ QRectF PileZone::boundingRect() const
|
|||
|
||||
void PileZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
||||
{
|
||||
qDebug("PileZone::paint");
|
||||
if (!cards->isEmpty()) {
|
||||
painter->save();
|
||||
cards->at(0)->paint(painter, option, widget);
|
||||
|
|
@ -47,7 +48,7 @@ void PileZone::handleDropEvent(int cardId, CardZone *startZone, const QPoint &/*
|
|||
void PileZone::reorganizeCards()
|
||||
{
|
||||
qDebug(QString("PileZone: reorganize, x=%1, y=%2, w=%3, h=%4").arg(boundingRect().x()).arg(boundingRect().y()).arg(boundingRect().width()).arg(boundingRect().height()).toLatin1());
|
||||
update(boundingRect());
|
||||
update();
|
||||
}
|
||||
|
||||
void PileZone::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@
|
|||
#include "playerarea.h"
|
||||
#include "counter.h"
|
||||
#include "zoneviewzone.h"
|
||||
#include "game.h"
|
||||
#include <QGraphicsScene>
|
||||
#include <QMenu>
|
||||
|
||||
Player::Player(const QString &_name, int _id, QPointF _base, bool _local, CardDatabase *_db, Client *_client, QGraphicsScene *_scene)
|
||||
: QObject(), defaultNumberTopCards(3), name(_name), id(_id), base(_base), local(_local), db(_db), client(_client)
|
||||
Player::Player(const QString &_name, int _id, QPointF _base, bool _local, CardDatabase *_db, Client *_client, QGraphicsScene *_scene, Game *_parent)
|
||||
: QObject(_parent), defaultNumberTopCards(3), name(_name), id(_id), base(_base), local(_local), db(_db), client(_client)
|
||||
{
|
||||
area = new PlayerArea(this);
|
||||
area->setPos(_base);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ class QMenu;
|
|||
class QAction;
|
||||
class PlayerArea;
|
||||
class ZoneViewZone;
|
||||
class Game;
|
||||
|
||||
class Player : public QObject {
|
||||
Q_OBJECT
|
||||
|
|
@ -57,7 +58,7 @@ public:
|
|||
PlayerArea *area;
|
||||
Client *client;
|
||||
void addZone(CardZone *z);
|
||||
Player(const QString &_name, int _id, QPointF _base, bool _local, CardDatabase *_db, Client *_client, QGraphicsScene *_scene);
|
||||
Player(const QString &_name, int _id, QPointF _base, bool _local, CardDatabase *_db, Client *_client, QGraphicsScene *_scene, Game *_parent);
|
||||
~Player();
|
||||
QMenu *getPlayerMenu() const { return playerMenu; }
|
||||
int getId() const { return id; }
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ void TableZone::addCardImpl(CardItem *card, int x, int y)
|
|||
qDebug(QString("table: appended %1 at pos %2: zValue = %3, x = %4, y = %5").arg(card->getName()).arg(cards->size() - 1).arg(card->zValue()).arg(x).arg(y).toLatin1());
|
||||
card->setParentItem(this);
|
||||
card->setVisible(true);
|
||||
card->update(card->boundingRect());
|
||||
card->update();
|
||||
}
|
||||
|
||||
void TableZone::handleDropEvent(int cardId, CardZone *startZone, const QPoint &dropPoint, bool faceDown)
|
||||
|
|
@ -55,9 +55,15 @@ void TableZone::reorganizeCards()
|
|||
|
||||
void TableZone::toggleTapped()
|
||||
{
|
||||
QListIterator<QGraphicsItem *> i(scene()->selectedItems());
|
||||
while (i.hasNext()) {
|
||||
CardItem *temp = (CardItem *) i.next();
|
||||
setCardAttr(temp->getId(), "tapped", temp->getTapped() ? "0" : "1");
|
||||
QList<QGraphicsItem *> selectedItems = scene()->selectedItems();
|
||||
bool tapAll = false;
|
||||
for (int i = 0; i < selectedItems.size(); i++)
|
||||
if (!qgraphicsitem_cast<CardItem *>(selectedItems[i])->getTapped()) {
|
||||
tapAll = true;
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < selectedItems.size(); i++) {
|
||||
CardItem *temp = qgraphicsitem_cast<CardItem *>(selectedItems[i]);
|
||||
setCardAttr(temp->getId(), "tapped", (!temp->getTapped() || tapAll) ? "1" : "0");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ void ZoneViewLayout::removeItem(ZoneViewWidget *item)
|
|||
{
|
||||
qDebug("ZoneViewLayout::removeItem");
|
||||
views.removeAt(views.indexOf(item));
|
||||
scene()->removeItem(item);
|
||||
reorganize();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ void ZoneViewZone::addCardImpl(CardItem *card, int x, int /*y*/)
|
|||
{
|
||||
cards->insert(x, card);
|
||||
card->setParentItem(this);
|
||||
card->update(card->boundingRect());
|
||||
card->update();
|
||||
}
|
||||
|
||||
void ZoneViewZone::handleDropEvent(int cardId, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/)
|
||||
|
|
@ -89,8 +89,7 @@ void ZoneViewZone::removeCard(int position)
|
|||
if (position >= cards->size())
|
||||
return;
|
||||
|
||||
CardItem *card = cards->at(position);
|
||||
cards->removeAt(position);
|
||||
CardItem *card = cards->takeAt(position);
|
||||
delete card;
|
||||
reorganizeCards();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ bool ReturnMessage::send(ReturnCode code)
|
|||
case ReturnSyntaxError: returnCodeString = "syntax"; break;
|
||||
case ReturnContextError: returnCodeString = "context"; break;
|
||||
case ReturnPasswordWrong: returnCodeString = "password"; break;
|
||||
case ReturnNameNotFound: returnCodeString = "name_not_found"; break;
|
||||
}
|
||||
s->msg(QString("resp|%1|%2|%3").arg(msg_id)
|
||||
.arg(success ? "ok" : "err")
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ private:
|
|||
unsigned int msg_id;
|
||||
QString cmd;
|
||||
public:
|
||||
enum ReturnCode { ReturnNothing, ReturnOk, ReturnLoginNeeded, ReturnSyntaxError, ReturnContextError, ReturnPasswordWrong, ReturnNameNotFound };
|
||||
enum ReturnCode { ReturnNothing, ReturnOk, ReturnLoginNeeded, ReturnSyntaxError, ReturnContextError, ReturnPasswordWrong };
|
||||
ReturnMessage(QObject *parent = 0) : QObject(parent), msg_id(0) { }
|
||||
unsigned int getMsgId() const { return msg_id; }
|
||||
void setMsgId(unsigned int _msg_id) { msg_id = _msg_id; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue