added deck hashing

This commit is contained in:
unknown 2011-10-04 16:55:18 +02:00
parent 963e8f0d90
commit 0bb4ef8bb8
31 changed files with 4867 additions and 4831 deletions

View file

@ -72,6 +72,7 @@
<file>resources/countries/fi.svg</file>
<file>resources/countries/fr.svg</file>
<file>resources/countries/gr.svg</file>
<file>resources/countries/gt.svg</file>
<file>resources/countries/hu.svg</file>
<file>resources/countries/ie.svg</file>
<file>resources/countries/il.svg</file>

View file

@ -17,6 +17,7 @@ DeckListModel::DeckListModel(QObject *parent)
{
deckList = new DeckList;
connect(deckList, SIGNAL(deckLoaded()), this, SLOT(rebuildTree()));
connect(deckList, SIGNAL(deckHashChanged()), this, SIGNAL(deckHashChanged()));
root = new InnerDecklistNode;
}
@ -194,6 +195,7 @@ bool DeckListModel::setData(const QModelIndex &index, const QVariant &value, int
default: return false;
}
emitRecursiveUpdates(index);
deckList->updateDeckHash();
return true;
}
@ -310,6 +312,8 @@ void DeckListModel::setDeckList(DeckList *_deck)
{
delete deckList;
deckList = _deck;
connect(deckList, SIGNAL(deckLoaded()), this, SLOT(rebuildTree()));
connect(deckList, SIGNAL(deckHashChanged()), this, SIGNAL(deckHashChanged()));
rebuildTree();
}

View file

@ -30,6 +30,8 @@ private slots:
void rebuildTree();
public slots:
void printDeckList(QPrinter *printer);
signals:
void deckHashChanged();
public:
DeckListModel(QObject *parent = 0);
~DeckListModel();

View file

@ -58,19 +58,12 @@ void MessageLogWidget::logLeaveSpectator(QString name)
appendHtml(tr("%1 is not watching the game any more.").arg(sanitizeHtml(name)));
}
void MessageLogWidget::logDeckSelect(Player *player, int deckId)
void MessageLogWidget::logDeckSelect(Player *player, QString deckHash)
{
if (deckId == -1) {
if (isFemale(player))
appendHtml(tr("%1 has loaded a local deck.", "female").arg(sanitizeHtml(player->getName())));
else
appendHtml(tr("%1 has loaded a local deck.", "male").arg(sanitizeHtml(player->getName())));
} else {
if (isFemale(player))
appendHtml(tr("%1 has loaded deck #%2.", "female").arg(sanitizeHtml(player->getName())).arg(deckId));
else
appendHtml(tr("%1 has loaded deck #%2.", "male").arg(sanitizeHtml(player->getName())).arg(deckId));
}
if (isFemale(player))
appendHtml(tr("%1 has loaded a deck (%2).", "female").arg(sanitizeHtml(player->getName())).arg(deckHash));
else
appendHtml(tr("%1 has loaded a deck (%2).", "male").arg(sanitizeHtml(player->getName())).arg(deckHash));
}
void MessageLogWidget::logReadyStart(Player *player)

View file

@ -46,7 +46,7 @@ public slots:
void logGameClosed();
void logJoinSpectator(QString name);
void logLeaveSpectator(QString name);
void logDeckSelect(Player *player, int deckId);
void logDeckSelect(Player *player, QString deckHash);
void logReadyStart(Player *player);
void logNotReadyStart(Player *player);
void logConcede(Player *player);

View file

@ -98,15 +98,7 @@ void PlayerListWidget::updatePlayerProperties(ServerInfo_PlayerProperties *prop)
player->setIcon(4, QIcon(CountryPixmapGenerator::generatePixmap(12, prop->getUserInfo()->getCountry())));
player->setData(4, Qt::UserRole, prop->getUserInfo()->getName());
player->setData(4, Qt::UserRole + 1, prop->getPlayerId());
QString deckText;
if (!prop->getSpectator())
switch (prop->getDeckId()) {
case -2: deckText = QString(); break;
case -1: deckText = tr("local deck"); break;
default: deckText = tr("deck #%1").arg(prop->getDeckId());
}
player->setText(5, deckText);
player->setText(5, prop->getDeckHash());
}
void PlayerListWidget::removePlayer(int playerId)

View file

@ -620,7 +620,7 @@ void TabGame::eventPlayerPropertiesChanged(Event_PlayerPropertiesChanged *event,
break;
}
case ItemId_Context_DeckSelect: messageLog->logDeckSelect(player, static_cast<Context_DeckSelect *>(context)->getDeckId()); break;
case ItemId_Context_DeckSelect: messageLog->logDeckSelect(player, static_cast<Context_DeckSelect *>(context)->getDeckHash()); break;
default: ;
}
}

View file

@ -99,6 +99,7 @@ WndDeckEditor::WndDeckEditor(QWidget *parent)
middleFrame->addLayout(verticalToolBarLayout);
deckModel = new DeckListModel(this);
connect(deckModel, SIGNAL(deckHashChanged()), this, SLOT(updateHash()));
deckView = new QTreeView();
deckView->setModel(deckModel);
deckView->setUniformRowHeights(true);
@ -114,6 +115,8 @@ WndDeckEditor::WndDeckEditor(QWidget *parent)
commentsEdit->setMaximumHeight(70);
commentsLabel->setBuddy(commentsEdit);
connect(commentsEdit, SIGNAL(textChanged()), this, SLOT(updateComments()));
QLabel *hashLabel1 = new QLabel(tr("Hash:"));
hashLabel = new QLabel;
QGridLayout *grid = new QGridLayout;
grid->addWidget(nameLabel, 0, 0);
@ -121,6 +124,9 @@ WndDeckEditor::WndDeckEditor(QWidget *parent)
grid->addWidget(commentsLabel, 1, 0);
grid->addWidget(commentsEdit, 1, 1);
grid->addWidget(hashLabel1, 2, 0);
grid->addWidget(hashLabel, 2, 1);
// Update price
aUpdatePrices = new QAction(tr("&Update prices"), this);
@ -140,10 +146,9 @@ WndDeckEditor::WndDeckEditor(QWidget *parent)
deckToolbarLayout->addWidget(deckToolBar);
deckToolbarLayout->addStretch();
QVBoxLayout *rightFrame = new QVBoxLayout;
rightFrame->addLayout(grid);
rightFrame->addWidget(deckView);
rightFrame->addWidget(deckView, 10);
rightFrame->addLayout(deckToolbarLayout);
QHBoxLayout *mainLayout = new QHBoxLayout;
@ -230,6 +235,7 @@ WndDeckEditor::WndDeckEditor(QWidget *parent)
verticalToolBar->addAction(aRemoveCard);
verticalToolBar->addAction(aIncrement);
verticalToolBar->addAction(aDecrement);
verticalToolBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
dlgCardSearch = new DlgCardSearch(this);
@ -273,6 +279,11 @@ void WndDeckEditor::updateSearch(const QString &search)
databaseView->selectionModel()->setCurrentIndex(databaseDisplayModel->index(0, 0), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
}
void WndDeckEditor::updateHash()
{
hashLabel->setText(deckModel->getDeckList()->getDeckHash());
}
bool WndDeckEditor::confirmClose()
{
if (isWindowModified()) {
@ -305,6 +316,7 @@ void WndDeckEditor::actNewDeck()
nameEdit->setText(QString());
commentsEdit->setText(QString());
lastFileName = QString();
setWindowModified(false);
}
void WndDeckEditor::actLoadDeck()
@ -506,6 +518,7 @@ void WndDeckEditor::setDeck(DeckList *_deck, const QString &_lastFileName, DeckL
lastFileFormat = _lastFileFormat;
nameEdit->setText(_deck->getName());
commentsEdit->setText(_deck->getComments());
updateHash();
deckModel->sort(1);
deckView->expandAll();
setWindowModified(false);

View file

@ -14,6 +14,7 @@ class QTableView;
class CardInfoWidget;
class QTextEdit;
class DlgCardSearch;
class QLabel;
class SearchLineEdit : public QLineEdit {
private:
@ -30,6 +31,7 @@ class WndDeckEditor : public QMainWindow {
private slots:
void updateName(const QString &name);
void updateComments();
void updateHash();
void updateCardInfoLeft(const QModelIndex &current, const QModelIndex &previous);
void updateCardInfoRight(const QModelIndex &current, const QModelIndex &previous);
void updateSearch(const QString &search);
@ -72,6 +74,7 @@ private:
SearchLineEdit *searchEdit;
QLineEdit *nameEdit;
QTextEdit *commentsEdit;
QLabel *hashLabel;
DlgCardSearch *dlgCardSearch;
QMenu *deckMenu, *dbMenu;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -3,6 +3,7 @@
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QVariant>
#include <QCryptographicHash>
#include "decklist.h"
MoveCardToZone::MoveCardToZone(const QString &_cardName, const QString &_startZone, const QString &_targetZone)
@ -263,6 +264,7 @@ DeckList::DeckList(DeckList *other)
newMoveList.append(new MoveCardToZone(oldMoveList[i]));
sideboardPlans.insert(spIterator.key(), new SideboardPlan(spIterator.key(), newMoveList));
}
updateDeckHash();
}
DeckList::~DeckList()
@ -453,8 +455,10 @@ bool DeckList::loadFromFile(const QString &fileName, FileFormat fmt)
case PlainTextFormat: result = loadFromFile_Plain(&file); break;
case CockatriceFormat: result = loadFromFile_Native(&file); break;
}
if (result)
if (result) {
updateDeckHash();
emit deckLoaded();
}
return result;
}
@ -486,6 +490,7 @@ void DeckList::cleanList()
root->clearTree();
setName();
setComments();
updateDeckHash();
}
void DeckList::getCardListHelper(InnerDecklistNode *item, QSet<QString> &result) const
@ -512,28 +517,55 @@ DecklistCardNode *DeckList::addCard(const QString &cardName, const QString &zone
if (!zoneNode)
zoneNode = new InnerDecklistNode(zoneName, root);
return new DecklistCardNode(cardName, 1, zoneNode);
DecklistCardNode *node = new DecklistCardNode(cardName, 1, zoneNode);
updateDeckHash();
return node;
}
bool DeckList::deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNode)
{
if (node == root)
return true;
if (!rootNode)
bool updateHash = false;
if (!rootNode) {
rootNode = root;
updateHash = true;
}
int index = rootNode->indexOf(node);
if (index != -1) {
delete rootNode->takeAt(index);
if (!rootNode->size())
deleteNode(rootNode, rootNode->getParent());
if (updateHash)
updateDeckHash();
return true;
}
for (int i = 0; i < rootNode->size(); i++) {
InnerDecklistNode *inner = dynamic_cast<InnerDecklistNode *>(rootNode->at(i));
if (inner)
if (deleteNode(node, inner))
if (deleteNode(node, inner)) {
if (updateHash)
updateDeckHash();
return true;
}
}
return false;
}
void DeckList::updateDeckHash()
{
QStringList cardList;
for (int i = 0; i < root->size(); i++) {
InnerDecklistNode *node = dynamic_cast<InnerDecklistNode *>(root->at(i));
for (int j = 0; j < node->size(); j++) {
DecklistCardNode *card = dynamic_cast<DecklistCardNode *>(node->at(j));
for (int k = 0; k < card->getNumber(); ++k)
cardList.append((node->getName() == "side" ? "SB:" : "") + card->getName().toLower());
}
}
cardList.sort();
deckHash = QCryptographicHash::hash(cardList.join(";").toUtf8(), QCryptographicHash::Sha1).toBase64().left(10);
emit deckHashChanged();
}

View file

@ -118,6 +118,7 @@ public:
private:
QString name, comments;
QString lastFileName;
QString deckHash;
FileFormat lastFileFormat;
QMap<QString, SideboardPlan *> sideboardPlans;
InnerDecklistNode *root;
@ -127,6 +128,7 @@ private:
void getCardListHelper(InnerDecklistNode *node, QSet<QString> &result) const;
signals:
void deckLoaded();
void deckHashChanged();
public slots:
void setName(const QString &_name = QString()) { name = _name; }
void setComments(const QString &_comments = QString()) { comments = _comments; }
@ -160,6 +162,9 @@ public:
void cleanList();
bool isEmpty() const { return root->isEmpty() && name.isEmpty() && comments.isEmpty() && sideboardPlans.isEmpty(); }
QStringList getCardList() const;
QString getDeckHash() const { return deckHash; }
void updateDeckHash();
InnerDecklistNode *getRoot() const { return root; }
DecklistCardNode *addCard(const QString &cardName, const QString &zoneName);

View file

@ -207,7 +207,7 @@ ServerInfo_Arrow::ServerInfo_Arrow(int _id, int _startPlayerId, const QString &_
insertItem(new SerializableItem_Color("color", _color));
}
ServerInfo_PlayerProperties::ServerInfo_PlayerProperties(int _playerId, ServerInfo_User *_userInfo, bool _spectator, bool _conceded, bool _readyStart, int _deckId)
ServerInfo_PlayerProperties::ServerInfo_PlayerProperties(int _playerId, ServerInfo_User *_userInfo, bool _spectator, bool _conceded, bool _readyStart, const QString &_deckHash)
: SerializableItem_Map("player_properties")
{
insertItem(new SerializableItem_Int("player_id", _playerId));
@ -217,7 +217,7 @@ ServerInfo_PlayerProperties::ServerInfo_PlayerProperties(int _playerId, ServerIn
insertItem(new SerializableItem_Bool("spectator", _spectator));
insertItem(new SerializableItem_Bool("conceded", _conceded));
insertItem(new SerializableItem_Bool("ready_start", _readyStart));
insertItem(new SerializableItem_Int("deck_id", _deckId));
insertItem(new SerializableItem_String("deck_hash", _deckHash));
}
ServerInfo_Player::ServerInfo_Player(ServerInfo_PlayerProperties *_properties, DeckList *_deck, const QList<ServerInfo_Zone *> &_zoneList, const QList<ServerInfo_Counter *> &_counterList, const QList<ServerInfo_Arrow *> &_arrowList)

View file

@ -189,14 +189,14 @@ public:
class ServerInfo_PlayerProperties : public SerializableItem_Map {
public:
ServerInfo_PlayerProperties(int _playerId = -1, ServerInfo_User *_userInfo = 0, bool _spectator = false, bool _conceded = false, bool _readyStart = false, int _deckId = -1);
ServerInfo_PlayerProperties(int _playerId = -1, ServerInfo_User *_userInfo = 0, bool _spectator = false, bool _conceded = false, bool _readyStart = false, const QString &_deckHash = QString());
static SerializableItem *newItem() { return new ServerInfo_PlayerProperties; }
int getPlayerId() const { return static_cast<SerializableItem_Int *>(itemMap.value("player_id"))->getData(); }
ServerInfo_User *getUserInfo() const { return static_cast<ServerInfo_User *>(itemMap.value("user")); }
bool getSpectator() const { return static_cast<SerializableItem_Bool *>(itemMap.value("spectator"))->getData(); }
bool getConceded() const { return static_cast<SerializableItem_Bool *>(itemMap.value("conceded"))->getData(); }
bool getReadyStart() const { return static_cast<SerializableItem_Bool *>(itemMap.value("ready_start"))->getData(); }
int getDeckId() const { return static_cast<SerializableItem_Int *>(itemMap.value("deck_id"))->getData(); }
QString getDeckHash() const { return static_cast<SerializableItem_String *>(itemMap.value("deck_hash"))->getData(); }
};
class ServerInfo_Player : public SerializableItem_Map {

View file

@ -461,10 +461,10 @@ Context_Concede::Context_Concede()
: GameEventContext("concede")
{
}
Context_DeckSelect::Context_DeckSelect(int _deckId)
Context_DeckSelect::Context_DeckSelect(const QString &_deckHash)
: GameEventContext("deck_select")
{
insertItem(new SerializableItem_Int("deck_id", _deckId));
insertItem(new SerializableItem_String("deck_hash", _deckHash));
}
Context_UndoDraw::Context_UndoDraw()
: GameEventContext("undo_draw")

View file

@ -75,7 +75,7 @@
5:room_say:s,player_name:s,message
6:ready_start
6:concede
6:deck_select:i,deck_id
6:deck_select:s,deck_hash
6:undo_draw
6:move_card
6:mulligan:i,number

View file

@ -697,8 +697,8 @@ public:
class Context_DeckSelect : public GameEventContext {
Q_OBJECT
public:
Context_DeckSelect(int _deckId = -1);
int getDeckId() const { return static_cast<SerializableItem_Int *>(itemMap.value("deck_id"))->getData(); };
Context_DeckSelect(const QString &_deckHash = QString());
QString getDeckHash() const { return static_cast<SerializableItem_String *>(itemMap.value("deck_hash"))->getData(); };
static SerializableItem *newItem() { return new Context_DeckSelect; }
int getItemId() const { return ItemId_Context_DeckSelect; }
};

View file

@ -11,7 +11,7 @@
#include <QDebug>
Server_Player::Server_Player(Server_Game *_game, int _playerId, ServerInfo_User *_userInfo, bool _spectator, Server_ProtocolHandler *_handler)
: game(_game), handler(_handler), userInfo(new ServerInfo_User(_userInfo)), deck(0), playerId(_playerId), spectator(_spectator), nextCardId(0), readyStart(false), conceded(false), deckId(-2)
: game(_game), handler(_handler), userInfo(new ServerInfo_User(_userInfo)), deck(0), playerId(_playerId), spectator(_spectator), nextCardId(0), readyStart(false), conceded(false)
{
}
@ -187,16 +187,15 @@ ServerInfo_PlayerProperties *Server_Player::getProperties()
{
QMutexLocker locker(&game->gameMutex);
return new ServerInfo_PlayerProperties(playerId, new ServerInfo_User(userInfo), spectator, conceded, readyStart, deckId);
return new ServerInfo_PlayerProperties(playerId, new ServerInfo_User(userInfo), spectator, conceded, readyStart, deck ? deck->getDeckHash() : QString());
}
void Server_Player::setDeck(DeckList *_deck, int _deckId)
void Server_Player::setDeck(DeckList *_deck)
{
QMutexLocker locker(&game->gameMutex);
delete deck;
deck = _deck;
deckId = _deckId;
}
void Server_Player::addZone(Server_CardZone *zone)

View file

@ -39,7 +39,6 @@ private:
int nextCardId;
bool readyStart;
bool conceded;
int deckId;
public:
Server_Player(Server_Game *_game, int _playerId, ServerInfo_User *_userInfo, bool _spectator, Server_ProtocolHandler *_handler);
~Server_Player();
@ -57,9 +56,8 @@ public:
bool getSpectator() const { return spectator; }
bool getConceded() const { return conceded; }
void setConceded(bool _conceded) { conceded = _conceded; }
int getDeckId() const { return deckId; }
ServerInfo_User *getUserInfo() const { return userInfo; }
void setDeck(DeckList *_deck, int _deckId);
void setDeck(DeckList *_deck);
DeckList *getDeck() const { return deck; }
Server_Game *getGame() const { return game; }
const QMap<QString, Server_CardZone *> &getZones() const { return zones; }

View file

@ -595,9 +595,9 @@ ResponseCode Server_ProtocolHandler::cmdDeckSelect(Command_DeckSelect *cmd, Comm
return r;
}
}
player->setDeck(deck, cmd->getDeckId());
player->setDeck(deck);
game->sendGameEvent(new Event_PlayerPropertiesChanged(player->getPlayerId(), player->getProperties()), new Context_DeckSelect(cmd->getDeckId()));
game->sendGameEvent(new Event_PlayerPropertiesChanged(player->getPlayerId(), player->getProperties()), new Context_DeckSelect(deck->getDeckHash()));
cont->setResponse(new Response_DeckDownload(cont->getCmdId(), RespOk, new DeckList(deck)));
return RespNothing;