Merge branch 'master' into valgrind

This commit is contained in:
Fabio Bas 2014-08-09 11:38:53 +02:00
commit 954489e6c0
105 changed files with 5903 additions and 4729 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@ tags
build* build*
*.qm *.qm
.directory .directory
mysql.cnf

View file

@ -76,8 +76,19 @@ IF(MSVC)
#set(CMAKE_CXX_FLAGS_DEBUG "/Zi") #set(CMAKE_CXX_FLAGS_DEBUG "/Zi")
ELSEIF (CMAKE_COMPILER_IS_GNUCXX) ELSEIF (CMAKE_COMPILER_IS_GNUCXX)
# linux/gcc, bsd/gcc, windows/mingw # linux/gcc, bsd/gcc, windows/mingw
include(CheckCXXCompilerFlag)
set(CMAKE_CXX_FLAGS_RELEASE "-s -O2") set(CMAKE_CXX_FLAGS_RELEASE "-s -O2")
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0 -Wall -Wextra -pedantic -Werror -Wcast-align -Wmissing-declarations -Winline -Wno-long-long -Wno-error=extra -Wno-error=unused-parameter -Wno-inline -Wno-error=delete-non-virtual-dtor -Wno-error=sign-compare -Wno-error=reorder -Wno-error=missing-declarations") set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0 -Wall -Wextra -pedantic -Werror")
set(ADDITIONAL_DEBUG_FLAGS -Wcast-align -Wmissing-declarations -Winline -Wno-long-long -Wno-error=extra -Wno-error=unused-parameter -Wno-inline -Wno-error=delete-non-virtual-dtor -Wno-error=sign-compare -Wno-error=reorder -Wno-error=missing-declarations)
FOREACH(FLAG ${ADDITIONAL_DEBUG_FLAGS})
CHECK_CXX_COMPILER_FLAG("${FLAG}" CXX_HAS_WARNING_${FLAG})
IF(CXX_HAS_WARNING_${FLAG})
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAG}")
ENDIF()
ENDFOREACH()
ELSE() ELSE()
# other: osx/llvm, bsd/llvm # other: osx/llvm, bsd/llvm
set(CMAKE_CXX_FLAGS_RELEASE "-O2") set(CMAKE_CXX_FLAGS_RELEASE "-O2")
@ -99,6 +110,11 @@ ENDIF()
IF(Qt5Widgets_FOUND) IF(Qt5Widgets_FOUND)
MESSAGE(STATUS "Found Qt ${Qt5Widgets_VERSION_STRING}") MESSAGE(STATUS "Found Qt ${Qt5Widgets_VERSION_STRING}")
if(UNIX AND NOT APPLE AND "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64")
# FIX: Qt was built with -reduce-relocations
add_definitions(-fPIC)
endif()
ELSE() ELSE()
FIND_PACKAGE(Qt4 4.8.0 REQUIRED) FIND_PACKAGE(Qt4 4.8.0 REQUIRED)
IF(QT4_FOUND) IF(QT4_FOUND)

134
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,134 @@
# Style Guide #
### Compatibility ###
Cockatrice is written in C++-03, so do not use C++11 constructs such as `auto`.
Cockatrice support both Qt 4 and Qt 5, so make sure that your code compiles
with both. If there have been breaking changes between Qt 4 and 5, use a
statement such as
#if QT_VERSION >= 0x500000
doSomethingWithQt5();
#else
doSomethingWithQt4();
#endif
For consistency, use Qt data structures where possible, such as `QString` over
`std::string` or `QList` over `std::vector`.
### Header files ###
Use header files with the extension `.h` and source files with the extension
`.cpp`.
Use header guards in the form of `FILE_NAME_H`.
Simple functions, such as getters, may be written inline in the header file,
but other functions should be written in the source file.
Keep library includes and project includes grouped together. So this is okay:
// Good:
#include <QList>
#include <QString>
#include "card.h"
#include "deck.h"
// Good:
#include "card.h"
#include "deck.h"
#include <QList>
#include <QString>
// Bad:
#include <QList>
#include "card.h"
#include <QString>
#include "deck.h"
### Naming ###
Use `UpperCamelCase` for classes, structs, enums, etc. and `lowerCamelCase` for
function and variable names.
Member variables aren't decorated in any way. Don't prefix or suffix with
underscores, etc.
For arguments to constructors which have the same names as member variables,
prefix those arguments with underscores:
MyClass::MyClass(int _myData)
: myData(_myData)
{}
Pointers and references should be denoted with the `*` or `&` going with the
variable name:
// Good:
Foo *foo1 = new Foo;
Foo &foo2 = *foo1;
// Bad:
Bar* bar1 = new Bar;
Bar& bar2 = *bar1;
Use `0` instead of `NULL` (or `nullptr`) for null pointers.
### Braces ###
Use K&R-style braces. Braces for function implementations go on their own
lines, but they go on the same line everywhere else:
int main()
{
if (someCondition) {
doSomething();
} else {
while (someOtherCondition) {
doSomethingElse();
}
}
}
Braces can be omitted for single-statement if's and the like, as long as it is
still legible.
### Tabs ###
Use only spaces. Four spaces per tab.
### Lines ###
Do not have trailing whitespace in your lines.
Lines should be 80 characters or less, as a soft limit.
### Memory Management ###
New code should be written using references over pointers and stack allocation
over heap allocation wherever possible.
// Good: uses stack allocation and references
void showCard(const Card &card);
int main()
{
Card card;
showCard(card);
}
// Bad: relies on manual memory management and doesn't give us much
// null-safety.
void showCard(const Card *card);
int main()
{
Card *card = new Card;
showCard(card);
delete card;
}
(Remember to pass by `const` reference wherever possible, to avoid accidentally
mutating objects.)
When pointers can't be avoided, try to use a smart pointer of some sort, such
as `QScopedPointer`, or, less preferably, `QSharedPointer`.

View file

@ -33,8 +33,11 @@ To compile:
The following flags can be passed to `cmake`: The following flags can be passed to `cmake`:
- `-DWITH_SERVER=1` build the server - `-DWITH_SERVER=1` Build the server
- `-DWITHOUT_CLIENT=1` do not build the client - `-DWITH_CLIENT=0` Do not build the client
- `-DWITH_ORACLE=0` Do not build Oracle
- `-DWITH_QT4=1` Force compilation to use Qt4 instead of Qt5.
- `-DCMAKE_BUILD_TYPE=Debug` Compile in debug mode. Enables extra logging output, debug symbols, and much more verbose compiler warnings.
# Running # Running

View file

@ -1,3 +1 @@
!define NSIS_PROJECT_NAME "@PROJECT_NAME@"
!define NSIS_SOURCE_PATH "@PROJECT_SOURCE_DIR@" !define NSIS_SOURCE_PATH "@PROJECT_SOURCE_DIR@"
!define NSIS_BINARY_PATH "@PROJECT_BINARY_DIR@"

View file

@ -2,10 +2,11 @@
!include "MUI2.nsh" !include "MUI2.nsh"
!include "FileFunc.nsh" !include "FileFunc.nsh"
Name "${NSIS_PROJECT_NAME}" Name "@CPACK_PACKAGE_NAME@"
OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@" OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@"
SetCompressor /SOLID lzma SetCompressor /SOLID lzma
InstallDir "$PROGRAMFILES\Cockatrice" InstallDir "$PROGRAMFILES\Cockatrice"
!define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@"
!define MUI_ABORTWARNING !define MUI_ABORTWARNING
!define MUI_WELCOMEFINISHPAGE_BITMAP "${NSIS_SOURCE_PATH}\cmake\leftimage.bmp" !define MUI_WELCOMEFINISHPAGE_BITMAP "${NSIS_SOURCE_PATH}\cmake\leftimage.bmp"
@ -35,7 +36,8 @@ Section "Application" SecApplication
SetShellVarContext all SetShellVarContext all
SetOutPath "$INSTDIR" SetOutPath "$INSTDIR"
File /r "${NSIS_BINARY_PATH}\Release\*.*" @CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS@
@CPACK_NSIS_FULL_INSTALL@
WriteUninstaller "$INSTDIR\uninstall.exe" WriteUninstaller "$INSTDIR\uninstall.exe"
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2

View file

@ -2,6 +2,7 @@ find_package(Git)
if(GIT_FOUND) if(GIT_FOUND)
execute_process( execute_process(
COMMAND ${GIT_EXECUTABLE} describe --long --always COMMAND ${GIT_EXECUTABLE} describe --long --always
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE res_var RESULT_VARIABLE res_var
OUTPUT_VARIABLE GIT_COM_ID OUTPUT_VARIABLE GIT_COM_ID
) )

View file

@ -13,6 +13,7 @@
#include <QNetworkReply> #include <QNetworkReply>
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QDebug> #include <QDebug>
#include <QImageReader>
const int CardDatabase::versionNeeded = 3; const int CardDatabase::versionNeeded = 3;
@ -92,6 +93,14 @@ bool PictureToLoad::nextSet()
return true; return true;
} }
QString PictureToLoad::getSetName() const
{
if (setIndex < sortedSets.size())
return sortedSets[setIndex]->getCorrectedShortName();
else
return QString("");
}
PictureLoader::PictureLoader(const QString &__picsPath, bool _picDownload, bool _picDownloadHq, QObject *parent) PictureLoader::PictureLoader(const QString &__picsPath, bool _picDownload, bool _picDownloadHq, QObject *parent)
: QObject(parent), : QObject(parent),
_picsPath(__picsPath), picDownload(_picDownload), picDownloadHq(_picDownloadHq), _picsPath(__picsPath), picDownload(_picDownload), picDownloadHq(_picDownloadHq),
@ -124,41 +133,90 @@ void PictureLoader::processLoadQueue()
} }
PictureToLoad ptl = loadQueue.takeFirst(); PictureToLoad ptl = loadQueue.takeFirst();
mutex.unlock(); mutex.unlock();
QString correctedName = ptl.getCard()->getCorrectedName();
QString picsPath = _picsPath; //The list of paths to the folders in which to search for images
QString setName = ptl.getSetName(); QList<QString> picsPaths = QList<QString>() << _picsPath + "/CUSTOM/" + ptl.getCard()->getCorrectedName() + ".full";
QString setName=ptl.getSetName();
if(!setName.isEmpty())
{
picsPaths << _picsPath + "/" + setName + "/" + ptl.getCard()->getCorrectedName() + ".full"
<< _picsPath + "/downloadedPics/" + setName + "/" + ptl.getCard()->getCorrectedName() + ".full";
}
QImage image; QImage image;
if (!image.load(QString("%1/%2/%3.full.jpg").arg(picsPath).arg(setName).arg(correctedName))) QImageReader imgReader;
if (!image.load(QString("%1/%2/%3%4.full.jpg").arg(picsPath).arg(setName).arg(correctedName).arg(1))) imgReader.setDecideFormatFromContent(true);
if (!image.load(QString("%1/%2/%3/%4.full.jpg").arg(picsPath).arg("downloadedPics").arg(setName).arg(correctedName))) { bool found = false;
if (picDownload) {
cardsToDownload.append(ptl);
if (!downloadRunning)
startNextPicDownload();
} else {
if (ptl.nextSet())
loadQueue.prepend(ptl);
else
emit imageLoaded(ptl.getCard(), QImage());
}
continue;
}
emit imageLoaded(ptl.getCard(), image); //Iterates through the list of paths, searching for images with the desired name with any QImageReader-supported extension
for (int i = 0; i < picsPaths.length() && !found; i ++) {
imgReader.setFileName(picsPaths.at(i));
if (imgReader.read(&image)) {
emit imageLoaded(ptl.getCard(), image);
found = true;
}
}
if (!found) {
if (picDownload) {
cardsToDownload.append(ptl);
if (!downloadRunning)
startNextPicDownload();
} else {
if (ptl.nextSet())
loadQueue.prepend(ptl);
else
emit imageLoaded(ptl.getCard(), QImage());
}
}
} }
} }
QString PictureLoader::getPicUrl(CardInfo *card) QString PictureLoader::getPicUrl(CardInfo *card)
{ {
if (!picDownload) return 0; if (!picDownload) return QString("");
QString picUrl = picDownloadHq ? settingsCache->getPicUrlHq() : settingsCache->getPicUrl();
picUrl.replace("!name!", QUrl::toPercentEncoding(card->getCorrectedName()));
CardSet *set = card->getPreferredSet(); CardSet *set = card->getPreferredSet();
picUrl.replace("!setcode!", QUrl::toPercentEncoding(set->getShortName())); QString picUrl = QString("");
picUrl.replace("!setname!", QUrl::toPercentEncoding(set->getLongName()));
picUrl.replace("!cardid!", QUrl::toPercentEncoding(QString::number(card->getPreferredMuId()))); // if sets have been defined for the card, they can contain custom picUrls
if(set)
{
// first check if Hq is enabled and a custom Hq card url exists in cards.xml
if(picDownloadHq)
{
picUrl = card->getCustomPicURLHq(set->getShortName());
if (!picUrl.isEmpty())
return picUrl;
}
// then, test for a custom, non-Hq card url in cards.xml
picUrl = card->getCustomPicURL(set->getShortName());
if (!picUrl.isEmpty())
return picUrl;
}
// otherwise, fallback to the default url
picUrl = picDownloadHq ? settingsCache->getPicUrlHq() : settingsCache->getPicUrl();
picUrl.replace("!name!", QUrl::toPercentEncoding(card->getCorrectedName()));
if (set) {
picUrl.replace("!setcode!", QUrl::toPercentEncoding(set->getShortName()));
picUrl.replace("!setname!", QUrl::toPercentEncoding(set->getLongName()));
}
int muid = card->getPreferredMuId();
if (muid)
picUrl.replace("!cardid!", QUrl::toPercentEncoding(QString::number(muid)));
if (picUrl.contains("!name!") ||
picUrl.contains("!setcode!") ||
picUrl.contains("!setname!") ||
picUrl.contains("!cardid!")) {
qDebug() << "Insufficient card data to download" << card->getName() << "Url:" << picUrl;
return QString("");
}
return picUrl; return picUrl;
} }
@ -175,8 +233,13 @@ void PictureLoader::startNextPicDownload()
cardBeingDownloaded = cardsToDownload.takeFirst(); cardBeingDownloaded = cardsToDownload.takeFirst();
// TODO: Do something useful when picUrl is 0 or empty, etc
QString picUrl = getPicUrl(cardBeingDownloaded.getCard()); QString picUrl = getPicUrl(cardBeingDownloaded.getCard());
if (picUrl.isEmpty()) {
qDebug() << "No url for" << cardBeingDownloaded.getCard()->getName();
cardBeingDownloaded = 0;
downloadRunning = false;
return;
}
QUrl url(picUrl); QUrl url(picUrl);
@ -192,29 +255,35 @@ void PictureLoader::picDownloadFinished(QNetworkReply *reply)
qDebug() << "Download failed:" << reply->errorString(); qDebug() << "Download failed:" << reply->errorString();
} }
const QByteArray &picData = reply->readAll(); const QByteArray &picData = reply->peek(reply->size()); //peek is used to keep the data in the buffer for use by QImageReader
QImage testImage; QImage testImage;
if (testImage.loadFromData(picData)) {
if (!QDir(QString(picsPath + "/downloadedPics/")).exists()) { QImageReader imgReader;
QDir dir(picsPath); imgReader.setDecideFormatFromContent(true);
if (!dir.exists()) imgReader.setDevice(reply);
QString extension = "." + imgReader.format(); //the format is determined prior to reading the QImageReader data into a QImage object, as that wipes the QImageReader buffer
if (extension == ".jpeg")
extension = ".jpg";
if (imgReader.read(&testImage)) {
QString setName = cardBeingDownloaded.getSetName();
if(!setName.isEmpty())
{
if (!QDir().mkpath(picsPath + "/downloadedPics/" + setName)) {
qDebug() << picsPath + "/downloadedPics/" + setName + " could not be created.";
return; return;
dir.mkdir("downloadedPics"); }
}
if (!QDir(QString(picsPath + "/downloadedPics/" + cardBeingDownloaded.getSetName())).exists()) {
QDir dir(QString(picsPath + "/downloadedPics"));
dir.mkdir(cardBeingDownloaded.getSetName());
}
QString suffix; QString suffix;
if (!cardBeingDownloaded.getStripped()) if (!cardBeingDownloaded.getStripped())
suffix = ".full"; suffix = ".full";
QFile newPic(picsPath + "/downloadedPics/" + cardBeingDownloaded.getSetName() + "/" + cardBeingDownloaded.getCard()->getCorrectedName() + suffix + ".jpg"); QFile newPic(picsPath + "/downloadedPics/" + setName + "/" + cardBeingDownloaded.getCard()->getCorrectedName() + suffix + extension);
if (!newPic.open(QIODevice::WriteOnly)) if (!newPic.open(QIODevice::WriteOnly))
return; return;
newPic.write(picData); newPic.write(picData);
newPic.close(); newPic.close();
}
emit imageLoaded(cardBeingDownloaded.getCard(), testImage); emit imageLoaded(cardBeingDownloaded.getCard(), testImage);
} else if (cardBeingDownloaded.getHq()) { } else if (cardBeingDownloaded.getHq()) {
@ -275,6 +344,8 @@ CardInfo::CardInfo(CardDatabase *_db,
bool _cipt, bool _cipt,
int _tableRow, int _tableRow,
const SetList &_sets, const SetList &_sets,
const QStringMap &_customPicURLs,
const QStringMap &_customPicURLsHq,
MuidMap _muIds) MuidMap _muIds)
: db(_db), : db(_db),
name(_name), name(_name),
@ -286,6 +357,8 @@ CardInfo::CardInfo(CardDatabase *_db,
text(_text), text(_text),
colors(_colors), colors(_colors),
loyalty(_loyalty), loyalty(_loyalty),
customPicURLs(_customPicURLs),
customPicURLsHq(_customPicURLsHq),
muIds(_muIds), muIds(_muIds),
cipt(_cipt), cipt(_cipt),
tableRow(_tableRow), tableRow(_tableRow),
@ -424,6 +497,8 @@ void CardInfo::updatePixmapCache()
CardSet* CardInfo::getPreferredSet() CardSet* CardInfo::getPreferredSet()
{ {
if(sets.isEmpty())
return 0;
SetList sortedSets = sets; SetList sortedSets = sets;
sortedSets.sortByKey(); sortedSets.sortByKey();
return sortedSets.first(); return sortedSets.first();
@ -431,7 +506,28 @@ CardSet* CardInfo::getPreferredSet()
int CardInfo::getPreferredMuId() int CardInfo::getPreferredMuId()
{ {
return muIds[getPreferredSet()->getShortName()]; CardSet *set = getPreferredSet();
return set ? muIds[set->getShortName()] : 0;
}
QString CardInfo::simplifyName(const QString &name) {
QString simpleName(name);
// So Aetherling would work, but not Ætherling since 'Æ' would get replaced
// with nothing.
simpleName.replace("æ", "ae");
simpleName.replace("Æ", "AE");
// Replace Jötun Grunt with Jotun Grunt.
simpleName = simpleName.normalized(QString::NormalizationForm_KD);
// Replace dashes with spaces so that we can say "garruk the veil cursed"
// instead of the unintuitive "garruk the veilcursed".
simpleName = simpleName.replace("-", " ");
simpleName.remove(QRegExp("[^a-zA-Z0-9 ]"));
simpleName = simpleName.toLower();
return simpleName;
} }
static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfo *info) static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfo *info)
@ -448,6 +544,14 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfo *info)
tmpSet=sets[i]->getShortName(); tmpSet=sets[i]->getShortName();
xml.writeAttribute("muId", QString::number(info->getMuId(tmpSet))); xml.writeAttribute("muId", QString::number(info->getMuId(tmpSet)));
tmpString = info->getCustomPicURL(tmpSet);
if(!tmpString.isEmpty())
xml.writeAttribute("picURL", tmpString);
tmpString = info->getCustomPicURLHq(tmpSet);
if(!tmpString.isEmpty())
xml.writeAttribute("picURLHq", tmpString);
xml.writeCharacters(tmpSet); xml.writeCharacters(tmpSet);
xml.writeEndElement(); xml.writeEndElement();
} }
@ -507,55 +611,55 @@ CardDatabase::~CardDatabase()
void CardDatabase::clear() void CardDatabase::clear()
{ {
QHashIterator<QString, CardSet *> setIt(setHash); QHashIterator<QString, CardSet *> setIt(sets);
while (setIt.hasNext()) { while (setIt.hasNext()) {
setIt.next(); setIt.next();
delete setIt.value(); delete setIt.value();
} }
setHash.clear(); sets.clear();
QHashIterator<QString, CardInfo *> i(cardHash); QHashIterator<QString, CardInfo *> i(cards);
while (i.hasNext()) { while (i.hasNext()) {
i.next(); i.next();
delete i.value(); delete i.value();
} }
cardHash.clear(); cards.clear();
// The pointers themselves were already deleted, so we don't delete them
// again.
simpleNameCards.clear();
} }
void CardDatabase::addCard(CardInfo *card) void CardDatabase::addCard(CardInfo *card)
{ {
cardHash.insert(card->getName(), card); cards.insert(card->getName(), card);
simpleNameCards.insert(CardInfo::simplifyName(card->getName()), card);
emit cardAdded(card); emit cardAdded(card);
} }
void CardDatabase::removeCard(CardInfo *card) void CardDatabase::removeCard(CardInfo *card)
{ {
cardHash.remove(card->getName()); cards.remove(card->getName());
simpleNameCards.remove(CardInfo::simplifyName(card->getName()));
emit cardRemoved(card); emit cardRemoved(card);
} }
CardInfo *CardDatabase::getCard(const QString &cardName, bool createIfNotFound) CardInfo *CardDatabase::getCard(const QString &cardName, bool createIfNotFound) {
{ return getCardFromMap(cards, cardName, createIfNotFound);
if (cardName.isEmpty()) }
return noCard;
else if (cardHash.contains(cardName)) CardInfo *CardDatabase::getCardBySimpleName(const QString &cardName, bool createIfNotFound) {
return cardHash.value(cardName); QString simpleName = CardInfo::simplifyName(cardName);
else if (createIfNotFound) { return getCardFromMap(simpleNameCards, simpleName, createIfNotFound);
CardInfo *newCard = new CardInfo(this, cardName, true);
newCard->addToSet(getSet("TK"));
cardHash.insert(cardName, newCard);
return newCard;
} else
return 0;
} }
CardSet *CardDatabase::getSet(const QString &setName) CardSet *CardDatabase::getSet(const QString &setName)
{ {
if (setHash.contains(setName)) if (sets.contains(setName))
return setHash.value(setName); return sets.value(setName);
else { else {
CardSet *newSet = new CardSet(setName); CardSet *newSet = new CardSet(setName);
setHash.insert(setName, newSet); sets.insert(setName, newSet);
return newSet; return newSet;
} }
} }
@ -563,7 +667,7 @@ CardSet *CardDatabase::getSet(const QString &setName)
SetList CardDatabase::getSetList() const SetList CardDatabase::getSetList() const
{ {
SetList result; SetList result;
QHashIterator<QString, CardSet *> i(setHash); QHashIterator<QString, CardSet *> i(sets);
while (i.hasNext()) { while (i.hasNext()) {
i.next(); i.next();
result << i.value(); result << i.value();
@ -573,7 +677,9 @@ SetList CardDatabase::getSetList() const
void CardDatabase::clearPixmapCache() void CardDatabase::clearPixmapCache()
{ {
QHashIterator<QString, CardInfo *> i(cardHash); // This also clears the cards in simpleNameCards since they point to the
// same object.
QHashIterator<QString, CardInfo *> i(cards);
while (i.hasNext()) { while (i.hasNext()) {
i.next(); i.next();
i.value()->clearPixmapCache(); i.value()->clearPixmapCache();
@ -597,7 +703,7 @@ void CardDatabase::loadSetsFromXml(QXmlStreamReader &xml)
else if (xml.name() == "longname") else if (xml.name() == "longname")
longName = xml.readElementText(); longName = xml.readElementText();
} }
setHash.insert(shortName, new CardSet(shortName, longName)); sets.insert(shortName, new CardSet(shortName, longName));
} }
} }
} }
@ -610,6 +716,7 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml)
if (xml.name() == "card") { if (xml.name() == "card") {
QString name, manacost, type, pt, text; QString name, manacost, type, pt, text;
QStringList colors; QStringList colors;
QStringMap customPicURLs, customPicURLsHq;
MuidMap muids; MuidMap muids;
SetList sets; SetList sets;
int tableRow = 0; int tableRow = 0;
@ -636,6 +743,12 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml)
if (attrs.hasAttribute("muId")) { if (attrs.hasAttribute("muId")) {
muids[setName] = attrs.value("muId").toString().toInt(); muids[setName] = attrs.value("muId").toString().toInt();
} }
if (attrs.hasAttribute("picURL")) {
customPicURLs[setName] = attrs.value("picURL").toString();
}
if (attrs.hasAttribute("picURLHq")) {
customPicURLsHq[setName] = attrs.value("picURLHq").toString();
}
} else if (xml.name() == "color") } else if (xml.name() == "color")
colors << xml.readElementText(); colors << xml.readElementText();
else if (xml.name() == "tablerow") else if (xml.name() == "tablerow")
@ -647,46 +760,32 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml)
else if (xml.name() == "token") else if (xml.name() == "token")
isToken = xml.readElementText().toInt(); isToken = xml.readElementText().toInt();
} }
cardHash.insert(name, new CardInfo(this, name, isToken, manacost, type, pt, text, colors, loyalty, cipt, tableRow, sets, muids)); addCard(new CardInfo(this, name, isToken, manacost, type, pt, text, colors, loyalty, cipt, tableRow, sets, customPicURLs, customPicURLsHq, muids));
} }
} }
} }
LoadStatus CardDatabase::loadFromFile(const QString &fileName, bool tokens) CardInfo *CardDatabase::getCardFromMap(CardNameMap &cardMap, const QString &cardName, bool createIfNotFound) {
if (cardName.isEmpty())
return noCard;
else if (cardMap.contains(cardName))
return cardMap.value(cardName);
else if (createIfNotFound) {
CardInfo *newCard = new CardInfo(this, cardName, true);
newCard->addToSet(getSet("TK"));
cardMap.insert(cardName, newCard);
return newCard;
} else
return 0;
}
LoadStatus CardDatabase::loadFromFile(const QString &fileName)
{ {
QFile file(fileName); QFile file(fileName);
file.open(QIODevice::ReadOnly); file.open(QIODevice::ReadOnly);
if (!file.isOpen()) if (!file.isOpen())
return FileError; return FileError;
if (tokens) {
QMutableHashIterator<QString, CardInfo *> i(cardHash);
while (i.hasNext()) {
i.next();
if (i.value()->getIsToken()) {
delete i.value();
i.remove();
}
}
} else {
QHashIterator<QString, CardSet *> setIt(setHash);
while (setIt.hasNext()) {
setIt.next();
delete setIt.value();
}
setHash.clear();
QMutableHashIterator<QString, CardInfo *> i(cardHash);
while (i.hasNext()) {
i.next();
if (!i.value()->getIsToken()) {
delete i.value();
i.remove();
}
}
cardHash.clear();
}
QXmlStreamReader xml(&file); QXmlStreamReader xml(&file);
while (!xml.atEnd()) { while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::StartElement) { if (xml.readNext() == QXmlStreamReader::StartElement) {
@ -707,9 +806,9 @@ LoadStatus CardDatabase::loadFromFile(const QString &fileName, bool tokens)
} }
} }
} }
qDebug() << cardHash.size() << "cards in" << setHash.size() << "sets loaded"; qDebug() << cards.size() << "cards in" << sets.size() << "sets loaded";
if (cardHash.isEmpty()) return NoCards; if (cards.isEmpty()) return NoCards;
return Ok; return Ok;
} }
@ -728,18 +827,17 @@ bool CardDatabase::saveToFile(const QString &fileName, bool tokens)
if (!tokens) { if (!tokens) {
xml.writeStartElement("sets"); xml.writeStartElement("sets");
QHashIterator<QString, CardSet *> setIterator(setHash); QHashIterator<QString, CardSet *> setIterator(sets);
while (setIterator.hasNext()) while (setIterator.hasNext())
xml << setIterator.next().value(); xml << setIterator.next().value();
xml.writeEndElement(); // sets xml.writeEndElement(); // sets
} }
xml.writeStartElement("cards"); xml.writeStartElement("cards");
QHashIterator<QString, CardInfo *> cardIterator(cardHash); QHashIterator<QString, CardInfo *> cardIterator(cards);
while (cardIterator.hasNext()) { while (cardIterator.hasNext()) {
CardInfo *card = cardIterator.next().value(); CardInfo *card = cardIterator.next().value();
if (card->getIsToken() == tokens) xml << card;
xml << card;
} }
xml.writeEndElement(); // cards xml.writeEndElement(); // cards
@ -753,7 +851,7 @@ void CardDatabase::picDownloadChanged()
{ {
pictureLoader->setPicDownload(settingsCache->getPicDownload()); pictureLoader->setPicDownload(settingsCache->getPicDownload());
if (settingsCache->getPicDownload()) { if (settingsCache->getPicDownload()) {
QHashIterator<QString, CardInfo *> cardIterator(cardHash); QHashIterator<QString, CardInfo *> cardIterator(cards);
while (cardIterator.hasNext()) while (cardIterator.hasNext())
cardIterator.next().value()->clearPixmapCacheMiss(); cardIterator.next().value()->clearPixmapCacheMiss();
} }
@ -763,7 +861,7 @@ void CardDatabase::picDownloadHqChanged()
{ {
pictureLoader->setPicDownloadHq(settingsCache->getPicDownloadHq()); pictureLoader->setPicDownloadHq(settingsCache->getPicDownloadHq());
if (settingsCache->getPicDownloadHq()) { if (settingsCache->getPicDownloadHq()) {
QHashIterator<QString, CardInfo *> cardIterator(cardHash); QHashIterator<QString, CardInfo *> cardIterator(cards);
while (cardIterator.hasNext()) while (cardIterator.hasNext())
cardIterator.next().value()->clearPixmapCacheMiss(); cardIterator.next().value()->clearPixmapCacheMiss();
} }
@ -773,11 +871,11 @@ LoadStatus CardDatabase::loadCardDatabase(const QString &path, bool tokens)
{ {
LoadStatus tempLoadStatus = NotLoaded; LoadStatus tempLoadStatus = NotLoaded;
if (!path.isEmpty()) if (!path.isEmpty())
tempLoadStatus = loadFromFile(path, tokens); tempLoadStatus = loadFromFile(path);
if (tempLoadStatus == Ok) { if (tempLoadStatus == Ok) {
SetList allSets; SetList allSets;
QHashIterator<QString, CardSet *> setsIterator(setHash); QHashIterator<QString, CardSet *> setsIterator(sets);
while (setsIterator.hasNext()) while (setsIterator.hasNext())
allSets.append(setsIterator.next().value()); allSets.append(setsIterator.next().value());
allSets.sortByKey(); allSets.sortByKey();
@ -809,7 +907,7 @@ void CardDatabase::loadTokenDatabase()
QStringList CardDatabase::getAllColors() const QStringList CardDatabase::getAllColors() const
{ {
QSet<QString> colors; QSet<QString> colors;
QHashIterator<QString, CardInfo *> cardIterator(cardHash); QHashIterator<QString, CardInfo *> cardIterator(cards);
while (cardIterator.hasNext()) { while (cardIterator.hasNext()) {
const QStringList &cardColors = cardIterator.next().value()->getColors(); const QStringList &cardColors = cardIterator.next().value()->getColors();
if (cardColors.isEmpty()) if (cardColors.isEmpty())
@ -824,7 +922,7 @@ QStringList CardDatabase::getAllColors() const
QStringList CardDatabase::getAllMainCardTypes() const QStringList CardDatabase::getAllMainCardTypes() const
{ {
QSet<QString> types; QSet<QString> types;
QHashIterator<QString, CardInfo *> cardIterator(cardHash); QHashIterator<QString, CardInfo *> cardIterator(cards);
while (cardIterator.hasNext()) while (cardIterator.hasNext())
types.insert(cardIterator.next().value()->getMainCardType()); types.insert(cardIterator.next().value()->getMainCardType());
return types.toList(); return types.toList();

View file

@ -55,7 +55,7 @@ public:
PictureToLoad(CardInfo *_card = 0, bool _stripped = false, bool _hq = true); PictureToLoad(CardInfo *_card = 0, bool _stripped = false, bool _hq = true);
CardInfo *getCard() const { return card; } CardInfo *getCard() const { return card; }
bool getStripped() const { return stripped; } bool getStripped() const { return stripped; }
QString getSetName() const { return sortedSets[setIndex]->getCorrectedShortName(); } QString getSetName() const;
bool nextSet(); bool nextSet();
bool getHq() const { return hq; } bool getHq() const { return hq; }
void setHq(bool _hq) { hq = _hq; } void setHq(bool _hq) { hq = _hq; }
@ -95,6 +95,13 @@ private:
CardDatabase *db; CardDatabase *db;
QString name; QString name;
/*
* The name without punctuation or capitalization, for better card tag name
* recognition.
*/
QString simpleName;
bool isToken; bool isToken;
SetList sets; SetList sets;
QString manacost; QString manacost;
@ -103,6 +110,7 @@ private:
QString text; QString text;
QStringList colors; QStringList colors;
int loyalty; int loyalty;
QStringMap customPicURLs, customPicURLsHq;
MuidMap muIds; MuidMap muIds;
bool cipt; bool cipt;
int tableRow; int tableRow;
@ -121,6 +129,8 @@ public:
bool _cipt = false, bool _cipt = false,
int _tableRow = 0, int _tableRow = 0,
const SetList &_sets = SetList(), const SetList &_sets = SetList(),
const QStringMap &_customPicURLs = QStringMap(),
const QStringMap &_customPicURLsHq = QStringMap(),
MuidMap muids = MuidMap()); MuidMap muids = MuidMap());
~CardInfo(); ~CardInfo();
const QString &getName() const { return name; } const QString &getName() const { return name; }
@ -138,12 +148,16 @@ public:
void setText(const QString &_text) { text = _text; emit cardInfoChanged(this); } void setText(const QString &_text) { text = _text; emit cardInfoChanged(this); }
void setColors(const QStringList &_colors) { colors = _colors; emit cardInfoChanged(this); } void setColors(const QStringList &_colors) { colors = _colors; emit cardInfoChanged(this); }
const QStringList &getColors() const { return colors; } const QStringList &getColors() const { return colors; }
QString getCustomPicURL(const QString &set) const { return customPicURLs.value(set); }
QString getCustomPicURLHq(const QString &set) const { return customPicURLsHq.value(set); }
int getMuId(const QString &set) const { return muIds.value(set); } int getMuId(const QString &set) const { return muIds.value(set); }
QString getMainCardType() const; QString getMainCardType() const;
QString getCorrectedName() const; QString getCorrectedName() const;
int getTableRow() const { return tableRow; } int getTableRow() const { return tableRow; }
void setTableRow(int _tableRow) { tableRow = _tableRow; } void setTableRow(int _tableRow) { tableRow = _tableRow; }
void setLoyalty(int _loyalty) { loyalty = _loyalty; emit cardInfoChanged(this); } void setLoyalty(int _loyalty) { loyalty = _loyalty; emit cardInfoChanged(this); }
void setCustomPicURL(const QString &_set, const QString &_customPicURL) { customPicURLs.insert(_set, _customPicURL); }
void setCustomPicURLHq(const QString &_set, const QString &_customPicURL) { customPicURLsHq.insert(_set, _customPicURL); }
void setMuId(const QString &_set, const int &_muId) { muIds.insert(_set, _muId); } void setMuId(const QString &_set, const int &_muId) { muIds.insert(_set, _muId); }
void addToSet(CardSet *set); void addToSet(CardSet *set);
QPixmap *loadPixmap(); QPixmap *loadPixmap();
@ -153,6 +167,12 @@ public:
void imageLoaded(const QImage &image); void imageLoaded(const QImage &image);
CardSet *getPreferredSet(); CardSet *getPreferredSet();
int getPreferredMuId(); int getPreferredMuId();
/**
* Simplify a name to have no punctuation and lowercase all letters, for
* less strict name-matching.
*/
static QString simplifyName(const QString &name);
public slots: public slots:
void updatePixmapCache(); void updatePixmapCache();
signals: signals:
@ -162,11 +182,27 @@ signals:
enum LoadStatus { Ok, VersionTooOld, Invalid, NotLoaded, FileError, NoCards }; enum LoadStatus { Ok, VersionTooOld, Invalid, NotLoaded, FileError, NoCards };
typedef QHash<QString, CardInfo *> CardNameMap;
typedef QHash<QString, CardSet *> SetNameMap;
class CardDatabase : public QObject { class CardDatabase : public QObject {
Q_OBJECT Q_OBJECT
protected: protected:
QHash<QString, CardInfo *> cardHash; /*
QHash<QString, CardSet *> setHash; * The cards, indexed by name.
*/
CardNameMap cards;
/**
* The cards, indexed by their simple name.
*/
CardNameMap simpleNameCards;
/*
* The sets, indexed by short name.
*/
SetNameMap sets;
CardInfo *noCard; CardInfo *noCard;
QThread *pictureLoaderThread; QThread *pictureLoaderThread;
@ -176,6 +212,8 @@ private:
static const int versionNeeded; static const int versionNeeded;
void loadCardsFromXml(QXmlStreamReader &xml); void loadCardsFromXml(QXmlStreamReader &xml);
void loadSetsFromXml(QXmlStreamReader &xml); void loadSetsFromXml(QXmlStreamReader &xml);
CardInfo *getCardFromMap(CardNameMap &cardMap, const QString &cardName, bool createIfNotFound);
public: public:
CardDatabase(QObject *parent = 0); CardDatabase(QObject *parent = 0);
~CardDatabase(); ~CardDatabase();
@ -183,10 +221,17 @@ public:
void addCard(CardInfo *card); void addCard(CardInfo *card);
void removeCard(CardInfo *card); void removeCard(CardInfo *card);
CardInfo *getCard(const QString &cardName = QString(), bool createIfNotFound = true); CardInfo *getCard(const QString &cardName = QString(), bool createIfNotFound = true);
/*
* Get a card by its simple name. The name will be simplified in this
* function, so you don't need to simplify it beforehand.
*/
CardInfo *getCardBySimpleName(const QString &cardName = QString(), bool createIfNotFound = true);
CardSet *getSet(const QString &setName); CardSet *getSet(const QString &setName);
QList<CardInfo *> getCardList() const { return cardHash.values(); } QList<CardInfo *> getCardList() const { return cards.values(); }
SetList getSetList() const; SetList getSetList() const;
LoadStatus loadFromFile(const QString &fileName, bool tokens = false); LoadStatus loadFromFile(const QString &fileName);
bool saveToFile(const QString &fileName, bool tokens = false); bool saveToFile(const QString &fileName, bool tokens = false);
QStringList getAllColors() const; QStringList getAllColors() const;
QStringList getAllMainCardTypes() const; QStringList getAllMainCardTypes() const;

View file

@ -81,7 +81,7 @@ CardInfoWidget::CardInfoWidget(ResizeMode _mode, const QString &cardName, QWidge
} else } else
setFixedWidth(250); setFixedWidth(250);
setCard(db->getCard(cardName)); setCard(getCard(cardName));
setMinimized(settingsCache->getCardInfoMinimized()); setMinimized(settingsCache->getCardInfoMinimized());
} }
@ -166,7 +166,7 @@ void CardInfoWidget::setCard(CardInfo *card)
void CardInfoWidget::setCard(const QString &cardName) void CardInfoWidget::setCard(const QString &cardName)
{ {
setCard(db->getCard(cardName)); setCard(getCard(cardName));
} }
void CardInfoWidget::setCard(AbstractCardItem *card) void CardInfoWidget::setCard(AbstractCardItem *card)
@ -176,7 +176,11 @@ void CardInfoWidget::setCard(AbstractCardItem *card)
void CardInfoWidget::clear() void CardInfoWidget::clear()
{ {
setCard(db->getCard()); setCard(getCard());
}
CardInfo *CardInfoWidget::getCard(const QString &cardName) {
return db->getCardBySimpleName(cardName);
} }
void CardInfoWidget::updatePixmap() void CardInfoWidget::updatePixmap()
@ -188,7 +192,7 @@ void CardInfoWidget::updatePixmap()
if (resizedPixmap) if (resizedPixmap)
cardPicture->setPixmap(*resizedPixmap); cardPicture->setPixmap(*resizedPixmap);
else else
cardPicture->setPixmap(*(db->getCard()->getPixmap(QSize(pixmapWidth, pixmapWidth * aspectRatio)))); cardPicture->setPixmap(*(getCard()->getPixmap(QSize(pixmapWidth, pixmapWidth * aspectRatio))));
} }
void CardInfoWidget::retranslateUi() void CardInfoWidget::retranslateUi()

View file

@ -42,6 +42,11 @@ private:
CardInfo *info; CardInfo *info;
void setMinimized(int _minimized); void setMinimized(int _minimized);
/*
* Wrapper around db->getCardBySimpleName.
*/
CardInfo *getCard(const QString &cardName = QString());
public: public:
CardInfoWidget(ResizeMode _mode, const QString &cardName = QString(), QWidget *parent = 0, Qt::WindowFlags f = 0); CardInfoWidget(ResizeMode _mode, const QString &cardName = QString(), QWidget *parent = 0, Qt::WindowFlags f = 0);
void retranslateUi(); void retranslateUi();

View file

@ -233,7 +233,8 @@ CardDragItem *CardItem::createDragItem(int _id, const QPointF &_pos, const QPoin
void CardItem::deleteDragItem() void CardItem::deleteDragItem()
{ {
dragItem->deleteLater(); if(dragItem)
dragItem->deleteLater();
dragItem = NULL; dragItem = NULL;
} }

View file

@ -472,13 +472,7 @@ void DeckListModel::printDeckList(QPrinter *printer)
doc.print(printer); doc.print(printer);
} }
void DeckListModel::pricesUpdated(InnerDecklistNode *node) void DeckListModel::pricesUpdated()
{ {
if (!node) emit layoutChanged();
node = root;
if (node->isEmpty())
return;
emit dataChanged(createIndex(0, 2, node->at(0)), createIndex(node->size() - 1, 2, node->last()));
} }

View file

@ -51,7 +51,7 @@ public:
void cleanList(); void cleanList();
DeckLoader *getDeckList() const { return deckList; } DeckLoader *getDeckList() const { return deckList; }
void setDeckList(DeckLoader *_deck); void setDeckList(DeckLoader *_deck);
void pricesUpdated(InnerDecklistNode *node = 0); void pricesUpdated();
private: private:
DeckLoader *deckList; DeckLoader *deckList;
InnerDecklistNode *root; InnerDecklistNode *root;

View file

@ -11,8 +11,10 @@
#include <QUrlQuery> #include <QUrlQuery>
#endif #endif
DeckStatsInterface::DeckStatsInterface(QObject *parent) DeckStatsInterface::DeckStatsInterface(
: QObject(parent) CardDatabase &_cardDatabase,
QObject *parent
) : QObject(parent), cardDatabase(_cardDatabase)
{ {
manager = new QNetworkAccessManager(this); manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(queryFinished(QNetworkReply *))); connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(queryFinished(QNetworkReply *)));
@ -43,24 +45,23 @@ void DeckStatsInterface::queryFinished(QNetworkReply *reply)
deleteLater(); deleteLater();
} }
void DeckStatsInterface::getAnalyzeRequestData(DeckList *deck, QByteArray *data)
{
DeckList deckWithoutTokens;
copyDeckWithoutTokens(*deck, deckWithoutTokens);
#if QT_VERSION < 0x050000 #if QT_VERSION < 0x050000
void DeckStatsInterface::getAnalyzeRequestData(DeckList *deck, QByteArray *data)
{
QUrl params; QUrl params;
params.addQueryItem("deck", deck->writeToString_Plain()); params.addQueryItem("deck", deckWithoutTokens.writeToString_Plain());
data->append(params.encodedQuery()); data->append(params.encodedQuery());
}
#else #else
void DeckStatsInterface::getAnalyzeRequestData(DeckList *deck, QByteArray *data)
{
QUrl params; QUrl params;
QUrlQuery urlQuery; QUrlQuery urlQuery;
urlQuery.addQueryItem("deck", deck->writeToString_Plain()); urlQuery.addQueryItem("deck", deckWithoutTokens.writeToString_Plain());
params.setQuery(urlQuery); params.setQuery(urlQuery);
data->append(params.query(QUrl::EncodeReserved)); data->append(params.query(QUrl::EncodeReserved));
}
#endif #endif
}
void DeckStatsInterface::analyzeDeck(DeckList *deck) void DeckStatsInterface::analyzeDeck(DeckList *deck)
{ {
@ -72,3 +73,34 @@ void DeckStatsInterface::analyzeDeck(DeckList *deck)
manager->post(request, data); manager->post(request, data);
} }
struct CopyIfNotAToken {
CardDatabase &cardDatabase;
DeckList &destination;
CopyIfNotAToken(
CardDatabase &_cardDatabase,
DeckList &_destination
) : cardDatabase(_cardDatabase), destination(_destination) {};
void operator()(
const InnerDecklistNode *node,
const DecklistCardNode *card
) const {
if (!cardDatabase.getCard(card->getName())->getIsToken()) {
DecklistCardNode *addedCard = destination.addCard(
card->getName(),
node->getName()
);
addedCard->setNumber(card->getNumber());
}
}
};
void DeckStatsInterface::copyDeckWithoutTokens(
const DeckList &source,
DeckList &destination
) {
CopyIfNotAToken copyIfNotAToken(cardDatabase, destination);
source.forEachCard(copyIfNotAToken);
}

View file

@ -1,6 +1,8 @@
#ifndef DECKSTATS_INTERFACE_H #ifndef DECKSTATS_INTERFACE_H
#define DECKSTATS_INTERFACE_H #define DECKSTATS_INTERFACE_H
#include "carddatabase.h"
#include "decklist.h"
#include <QObject> #include <QObject>
class QByteArray; class QByteArray;
@ -12,11 +14,21 @@ class DeckStatsInterface : public QObject {
Q_OBJECT Q_OBJECT
private: private:
QNetworkAccessManager *manager; QNetworkAccessManager *manager;
CardDatabase &cardDatabase;
/**
* Deckstats doesn't recognize token cards, and instead tries to find the
* closest non-token card instead. So we construct a new deck which has no
* tokens.
*/
void copyDeckWithoutTokens(const DeckList &source, DeckList& destination);
private slots: private slots:
void queryFinished(QNetworkReply *reply); void queryFinished(QNetworkReply *reply);
void getAnalyzeRequestData(DeckList *deck, QByteArray *data); void getAnalyzeRequestData(DeckList *deck, QByteArray *data);
public: public:
DeckStatsInterface(QObject *parent = 0); DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent = 0);
void analyzeDeck(DeckList *deck); void analyzeDeck(DeckList *deck);
}; };

View file

@ -113,7 +113,7 @@ DlgEditTokens::DlgEditTokens(CardDatabaseModel *_cardDatabaseModel, QWidget *par
setWindowTitle(tr("Edit tokens")); setWindowTitle(tr("Edit tokens"));
} }
void DlgEditTokens::tokenSelectionChanged(const QModelIndex &current, const QModelIndex &previous) void DlgEditTokens::tokenSelectionChanged(const QModelIndex &current, const QModelIndex & /* previous */)
{ {
const QModelIndex realIndex = cardDatabaseDisplayModel->mapToSource(current); const QModelIndex realIndex = cardDatabaseDisplayModel->mapToSource(current);
CardInfo *cardInfo = current.row() >= 0 ? cardDatabaseModel->getCard(realIndex.row()) : cardDatabaseModel->getDatabase()->getCard(); CardInfo *cardInfo = current.row() >= 0 ? cardDatabaseModel->getCard(realIndex.row()) : cardDatabaseModel->getDatabase()->getCard();

View file

@ -9,26 +9,53 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QGridLayout> #include <QGridLayout>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QSettings>
#include <QCryptographicHash>
DlgFilterGames::DlgFilterGames(const QMap<int, QString> &allGameTypes, QWidget *parent) DlgFilterGames::DlgFilterGames(const QMap<int, QString> &_allGameTypes, QWidget *parent)
: QDialog(parent) : QDialog(parent),
allGameTypes(_allGameTypes)
{ {
unavailableGamesVisibleCheckBox = new QCheckBox(tr("Show &unavailable games")); QSettings settings;
passwordProtectedGamesVisibleCheckBox = new QCheckBox(tr("Show &password protected games")); settings.beginGroup("filter_games");
unavailableGamesVisibleCheckBox = new QCheckBox(tr("Show &unavailable games"));
unavailableGamesVisibleCheckBox->setChecked(
settings.value("unavailable_games_visible", false).toBool()
);
passwordProtectedGamesVisibleCheckBox = new QCheckBox(tr("Show &password protected games"));
passwordProtectedGamesVisibleCheckBox->setChecked(
settings.value("password_protected_games_visible", false).toBool()
);
QLabel *gameNameFilterLabel = new QLabel(tr("Game &description:"));
gameNameFilterEdit = new QLineEdit; gameNameFilterEdit = new QLineEdit;
gameNameFilterEdit->setText(
settings.value("game_name_filter", "").toString()
);
QLabel *gameNameFilterLabel = new QLabel(tr("Game &description:"));
gameNameFilterLabel->setBuddy(gameNameFilterEdit); gameNameFilterLabel->setBuddy(gameNameFilterEdit);
QLabel *creatorNameFilterLabel = new QLabel(tr("&Creator name:"));
creatorNameFilterEdit = new QLineEdit; creatorNameFilterEdit = new QLineEdit;
creatorNameFilterEdit->setText(
settings.value("creator_name_filter", "").toString()
);
QLabel *creatorNameFilterLabel = new QLabel(tr("&Creator name:"));
creatorNameFilterLabel->setBuddy(creatorNameFilterEdit); creatorNameFilterLabel->setBuddy(creatorNameFilterEdit);
QVBoxLayout *gameTypeFilterLayout = new QVBoxLayout; QVBoxLayout *gameTypeFilterLayout = new QVBoxLayout;
QMapIterator<int, QString> gameTypesIterator(allGameTypes); QMapIterator<int, QString> gameTypesIterator(allGameTypes);
while (gameTypesIterator.hasNext()) { while (gameTypesIterator.hasNext()) {
gameTypesIterator.next(); gameTypesIterator.next();
QCheckBox *temp = new QCheckBox(gameTypesIterator.value()); QCheckBox *temp = new QCheckBox(gameTypesIterator.value());
temp->setChecked(
settings.value(
"game_type/" + hashGameType(gameTypesIterator.value()),
false
).toBool()
);
gameTypeFilterCheckBoxes.insert(gameTypesIterator.key(), temp); gameTypeFilterCheckBoxes.insert(gameTypesIterator.key(), temp);
gameTypeFilterLayout->addWidget(temp); gameTypeFilterLayout->addWidget(temp);
} }
@ -43,14 +70,18 @@ DlgFilterGames::DlgFilterGames(const QMap<int, QString> &allGameTypes, QWidget *
maxPlayersFilterMinSpinBox = new QSpinBox; maxPlayersFilterMinSpinBox = new QSpinBox;
maxPlayersFilterMinSpinBox->setMinimum(1); maxPlayersFilterMinSpinBox->setMinimum(1);
maxPlayersFilterMinSpinBox->setMaximum(99); maxPlayersFilterMinSpinBox->setMaximum(99);
maxPlayersFilterMinSpinBox->setValue(1); maxPlayersFilterMinSpinBox->setValue(
settings.value("min_players", 1).toInt()
);
maxPlayersFilterMinLabel->setBuddy(maxPlayersFilterMinSpinBox); maxPlayersFilterMinLabel->setBuddy(maxPlayersFilterMinSpinBox);
QLabel *maxPlayersFilterMaxLabel = new QLabel(tr("at &most:")); QLabel *maxPlayersFilterMaxLabel = new QLabel(tr("at &most:"));
maxPlayersFilterMaxSpinBox = new QSpinBox; maxPlayersFilterMaxSpinBox = new QSpinBox;
maxPlayersFilterMaxSpinBox->setMinimum(1); maxPlayersFilterMaxSpinBox->setMinimum(1);
maxPlayersFilterMaxSpinBox->setMaximum(99); maxPlayersFilterMaxSpinBox->setMaximum(99);
maxPlayersFilterMaxSpinBox->setValue(99); maxPlayersFilterMaxSpinBox->setValue(
settings.value("max_players", 99).toInt()
);
maxPlayersFilterMaxLabel->setBuddy(maxPlayersFilterMaxSpinBox); maxPlayersFilterMaxLabel->setBuddy(maxPlayersFilterMaxSpinBox);
QGridLayout *maxPlayersFilterLayout = new QGridLayout; QGridLayout *maxPlayersFilterLayout = new QGridLayout;
@ -83,7 +114,7 @@ DlgFilterGames::DlgFilterGames(const QMap<int, QString> &allGameTypes, QWidget *
hbox->addLayout(rightColumn); hbox->addLayout(rightColumn);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOk()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
QVBoxLayout *mainLayout = new QVBoxLayout; QVBoxLayout *mainLayout = new QVBoxLayout;
@ -94,6 +125,42 @@ DlgFilterGames::DlgFilterGames(const QMap<int, QString> &allGameTypes, QWidget *
setWindowTitle(tr("Filter games")); setWindowTitle(tr("Filter games"));
} }
void DlgFilterGames::actOk() {
QSettings settings;
settings.beginGroup("filter_games");
settings.setValue(
"unavailable_games_visible",
unavailableGamesVisibleCheckBox->isChecked()
);
settings.setValue(
"password_protected_games_visible",
passwordProtectedGamesVisibleCheckBox->isChecked()
);
settings.setValue("game_name_filter", gameNameFilterEdit->text());
settings.setValue("creator_name_filter", creatorNameFilterEdit->text());
QMapIterator<int, QString> gameTypeIterator(allGameTypes);
QMapIterator<int, QCheckBox *> checkboxIterator(gameTypeFilterCheckBoxes);
while (gameTypeIterator.hasNext()) {
gameTypeIterator.next();
checkboxIterator.next();
settings.setValue(
"game_type/" + hashGameType(gameTypeIterator.value()),
checkboxIterator.value()->isChecked()
);
}
settings.setValue("min_players", maxPlayersFilterMinSpinBox->value());
settings.setValue("max_players", maxPlayersFilterMaxSpinBox->value());
accept();
}
QString DlgFilterGames::hashGameType(const QString &gameType) const {
return QCryptographicHash::hash(gameType.toUtf8(), QCryptographicHash::Md5).toHex();
}
bool DlgFilterGames::getUnavailableGamesVisible() const bool DlgFilterGames::getUnavailableGamesVisible() const
{ {
return unavailableGamesVisibleCheckBox->isChecked(); return unavailableGamesVisibleCheckBox->isChecked();

View file

@ -19,6 +19,16 @@ private:
QMap<int, QCheckBox *> gameTypeFilterCheckBoxes; QMap<int, QCheckBox *> gameTypeFilterCheckBoxes;
QSpinBox *maxPlayersFilterMinSpinBox; QSpinBox *maxPlayersFilterMinSpinBox;
QSpinBox *maxPlayersFilterMaxSpinBox; QSpinBox *maxPlayersFilterMaxSpinBox;
const QMap<int, QString> &allGameTypes;
/*
* The game type might contain special characters, so to use it in
* QSettings we just hash it.
*/
QString hashGameType(const QString &gameType) const;
private slots:
void actOk();
public: public:
DlgFilterGames(const QMap<int, QString> &allGameTypes, QWidget *parent = 0); DlgFilterGames(const QMap<int, QString> &allGameTypes, QWidget *parent = 0);

View file

@ -18,11 +18,13 @@
#include <QInputDialog> #include <QInputDialog>
#include <QSpinBox> #include <QSpinBox>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QRadioButton>
#include <QDebug> #include <QDebug>
#include "carddatabase.h" #include "carddatabase.h"
#include "dlg_settings.h" #include "dlg_settings.h"
#include "main.h" #include "main.h"
#include "settingscache.h" #include "settingscache.h"
#include "priceupdater.h"
GeneralSettingsPage::GeneralSettingsPage() GeneralSettingsPage::GeneralSettingsPage()
{ {
@ -532,8 +534,29 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
priceTagsCheckBox->setChecked(settingsCache->getPriceTagFeature()); priceTagsCheckBox->setChecked(settingsCache->getPriceTagFeature());
connect(priceTagsCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPriceTagFeature(int))); connect(priceTagsCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPriceTagFeature(int)));
priceTagSource0 = new QRadioButton;
priceTagSource1 = new QRadioButton;
switch(settingsCache->getPriceTagSource())
{
case AbstractPriceUpdater::DBPriceSource:
priceTagSource1->setChecked(true);
break;
case AbstractPriceUpdater::BLPPriceSource:
default:
priceTagSource0->setChecked(true);
break;
}
connect(priceTagSource0, SIGNAL(toggled(bool)), this, SLOT(radioPriceTagSourceClicked(bool)));
connect(priceTagSource1, SIGNAL(toggled(bool)), this, SLOT(radioPriceTagSourceClicked(bool)));
connect(this, SIGNAL(priceTagSourceChanged(int)), settingsCache, SLOT(setPriceTagSource(int)));
QGridLayout *generalGrid = new QGridLayout; QGridLayout *generalGrid = new QGridLayout;
generalGrid->addWidget(priceTagsCheckBox, 0, 0); generalGrid->addWidget(priceTagsCheckBox, 0, 0);
generalGrid->addWidget(priceTagSource0, 1, 0);
generalGrid->addWidget(priceTagSource1, 2, 0);
generalGroupBox = new QGroupBox; generalGroupBox = new QGroupBox;
generalGroupBox->setLayout(generalGrid); generalGroupBox->setLayout(generalGrid);
@ -546,10 +569,26 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
void DeckEditorSettingsPage::retranslateUi() void DeckEditorSettingsPage::retranslateUi()
{ {
priceTagsCheckBox->setText(tr("Enable &price tag feature (using data from blacklotusproject.com)")); priceTagsCheckBox->setText(tr("Enable &price tag feature"));
priceTagSource0->setText(tr("using data from blacklotusproject.com"));
priceTagSource1->setText(tr("using data from deckbrew.com"));
generalGroupBox->setTitle(tr("General")); generalGroupBox->setTitle(tr("General"));
} }
void DeckEditorSettingsPage::radioPriceTagSourceClicked(bool checked)
{
if(!checked)
return;
int source=AbstractPriceUpdater::BLPPriceSource;
if(priceTagSource0->isChecked())
source=AbstractPriceUpdater::BLPPriceSource;
if(priceTagSource1->isChecked())
source=AbstractPriceUpdater::DBPriceSource;
emit priceTagSourceChanged(source);
}
MessagesSettingsPage::MessagesSettingsPage() MessagesSettingsPage::MessagesSettingsPage()
{ {
aAdd = new QAction(this); aAdd = new QAction(this);

View file

@ -15,6 +15,7 @@ class QCheckBox;
class QLabel; class QLabel;
class QCloseEvent; class QCloseEvent;
class QSpinBox; class QSpinBox;
class QRadioButton;
class AbstractSettingsPage : public QWidget { class AbstractSettingsPage : public QWidget {
public: public:
@ -100,8 +101,13 @@ class DeckEditorSettingsPage : public AbstractSettingsPage {
public: public:
DeckEditorSettingsPage(); DeckEditorSettingsPage();
void retranslateUi(); void retranslateUi();
private slots:
void radioPriceTagSourceClicked(bool checked);
signals:
void priceTagSourceChanged(int _priceTagSource);
private: private:
QCheckBox *priceTagsCheckBox; QCheckBox *priceTagsCheckBox;
QRadioButton *priceTagSource0, *priceTagSource1;
QGroupBox *generalGroupBox; QGroupBox *generalGroupBox;
}; };

View file

@ -18,10 +18,10 @@ public:
virtual void enable() { enabled = true; nodeChanged(); } virtual void enable() { enabled = true; nodeChanged(); }
virtual void disable() { enabled = false; nodeChanged(); } virtual void disable() { enabled = false; nodeChanged(); }
virtual FilterTreeNode *parent() const { return NULL; } virtual FilterTreeNode *parent() const { return NULL; }
virtual FilterTreeNode *nodeAt(int i) const { return NULL; } virtual FilterTreeNode *nodeAt(int /* i */) const { return NULL; }
virtual void deleteAt(int i) {} virtual void deleteAt(int /* i */) {}
virtual int childCount() const { return 0; } virtual int childCount() const { return 0; }
virtual int childIndex(const FilterTreeNode *node) const { return -1; } virtual int childIndex(const FilterTreeNode * /* node */) const { return -1; }
virtual int index() const { return (parent() != NULL)? parent()->childIndex(this) : -1; } virtual int index() const { return (parent() != NULL)? parent()->childIndex(this) : -1; }
virtual QString text() const { return QString(textCStr()); } virtual QString text() const { return QString(textCStr()); }
virtual bool isLeaf() const { return false; } virtual bool isLeaf() const { return false; }
@ -48,7 +48,7 @@ class FilterTreeBranch : public FilterTreeNode {
protected: protected:
QList<T> childNodes; QList<T> childNodes;
public: public:
~FilterTreeBranch(); virtual ~FilterTreeBranch();
FilterTreeNode *nodeAt(int i) const; FilterTreeNode *nodeAt(int i) const;
void deleteAt(int i); void deleteAt(int i);
int childCount() const { return childNodes.size(); } int childCount() const { return childNodes.size(); }
@ -102,6 +102,7 @@ public:
FilterItem(QString trm, FilterItemList *parent) FilterItem(QString trm, FilterItemList *parent)
: p(parent), term(trm) {} : p(parent), term(trm) {}
virtual ~FilterItem() {};
CardFilter::Attr attr() const { return p->attr(); } CardFilter::Attr attr() const { return p->attr(); }
CardFilter::Type type() const { return p->type; } CardFilter::Type type() const { return p->type; }

View file

@ -84,12 +84,6 @@ void GameSelector::actSetFilter()
if (room) if (room)
gameTypeMap = gameListModel->getGameTypes().value(room->getRoomId()); gameTypeMap = gameListModel->getGameTypes().value(room->getRoomId());
DlgFilterGames dlg(gameTypeMap, this); DlgFilterGames dlg(gameTypeMap, this);
dlg.setUnavailableGamesVisible(gameListProxyModel->getUnavailableGamesVisible());
dlg.setPasswordProtectedGamesVisible(gameListProxyModel->getPasswordProtectedGamesVisible());
dlg.setGameNameFilter(gameListProxyModel->getGameNameFilter());
dlg.setCreatorNameFilter(gameListProxyModel->getCreatorNameFilter());
dlg.setGameTypeFilter(gameListProxyModel->getGameTypeFilter());
dlg.setMaxPlayersFilter(gameListProxyModel->getMaxPlayersFilterMin(), gameListProxyModel->getMaxPlayersFilterMax());
if (!dlg.exec()) if (!dlg.exec())
return; return;

View file

@ -33,7 +33,7 @@ ServerInfo_User LocalServer_DatabaseInterface::getUserData(const QString &name,
return result; return result;
} }
AuthenticationResult LocalServer_DatabaseInterface::checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &secondsLeft) AuthenticationResult LocalServer_DatabaseInterface::checkUserPassword(Server_ProtocolHandler * /* handler */, const QString & /* user */, const QString & /* password */, QString & /* reasonStr */, int & /* secondsLeft */)
{ {
return UnknownUser; return UnknownUser;
} }

View file

@ -30,6 +30,7 @@
#include <QIcon> #include <QIcon>
#include <QDir> #include <QDir>
#include <QDesktopServices> #include <QDesktopServices>
#include <QDebug>
#include "main.h" #include "main.h"
#include "window_main.h" #include "window_main.h"
@ -158,6 +159,8 @@ int main(int argc, char *argv[])
QDir().mkpath(dataDir + "/pics"); QDir().mkpath(dataDir + "/pics");
settingsCache->setPicsPath(dataDir + "/pics"); settingsCache->setPicsPath(dataDir + "/pics");
} }
if (!QDir().mkpath(settingsCache->getPicsPath() + "/CUSTOM"))
qDebug() << "Could not create " + settingsCache->getPicsPath().toUtf8() + "/CUSTOM. Will fall back on default card images.";
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
if(settingsCache->getHandBgPath().isEmpty() && if(settingsCache->getHandBgPath().isEmpty() &&

View file

@ -959,6 +959,10 @@ void Player::actCreateToken()
return; return;
lastTokenName = dlg.getName(); lastTokenName = dlg.getName();
if (CardInfo *correctedCard = db->getCardBySimpleName(lastTokenName, false)) {
lastTokenName = correctedCard->getName();
}
lastTokenColor = dlg.getColor(); lastTokenColor = dlg.getColor();
lastTokenPT = dlg.getPT(); lastTokenPT = dlg.getPT();
lastTokenAnnotation = dlg.getAnnotation(); lastTokenAnnotation = dlg.getAnnotation();

View file

@ -178,5 +178,5 @@ void PlayerListWidget::showContextMenu(const QPoint &pos, const QModelIndex &ind
int playerId = index.sibling(index.row(), 4).data(Qt::UserRole + 1).toInt(); int playerId = index.sibling(index.row(), 4).data(Qt::UserRole + 1).toInt();
UserLevelFlags userLevel(index.sibling(index.row(), 3).data(Qt::UserRole).toInt()); UserLevelFlags userLevel(index.sibling(index.row(), 3).data(Qt::UserRole).toInt());
userContextMenu->showContextMenu(pos, userName, userLevel, playerId); userContextMenu->showContextMenu(pos, userName, userLevel, true, playerId);
} }

View file

@ -4,25 +4,46 @@
*/ */
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QNetworkReply> #include <QNetworkReply>
#include <QMessageBox>
#include "qt-json/json.h" #include "qt-json/json.h"
#include "priceupdater.h" #include "priceupdater.h"
#include "main.h"
#include "carddatabase.h"
#if QT_VERSION < 0x050000
// for Qt::escape()
#include <QtGui/qtextdocument.h>
#endif
/** /**
* Constructor. * Constructor.
* *
* @param _deck deck. * @param _deck deck.
*/ */
PriceUpdater::PriceUpdater(const DeckList *_deck) AbstractPriceUpdater::AbstractPriceUpdater(const DeckList *_deck)
{ {
nam = new QNetworkAccessManager(this); nam = new QNetworkAccessManager(this);
deck = _deck; deck = _deck;
} }
// blacklotusproject.com
/**
* Constructor.
*
* @param _deck deck.
*/
BLPPriceUpdater::BLPPriceUpdater(const DeckList *_deck)
: AbstractPriceUpdater(_deck)
{
}
/** /**
* Update the prices of the cards in deckList. * Update the prices of the cards in deckList.
*/ */
void PriceUpdater::updatePrices() void BLPPriceUpdater::updatePrices()
{ {
QString q = "http://blacklotusproject.com/json/?cards="; QString q = "http://blacklotusproject.com/json/?cards=";
QStringList cards = deck->getCardList(); QStringList cards = deck->getCardList();
@ -38,7 +59,7 @@ void PriceUpdater::updatePrices()
/** /**
* Called when the download of the json file with the prices is finished. * Called when the download of the json file with the prices is finished.
*/ */
void PriceUpdater::downloadFinished() void BLPPriceUpdater::downloadFinished()
{ {
QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
bool ok; bool ok;
@ -82,3 +103,188 @@ void PriceUpdater::downloadFinished()
deleteLater(); deleteLater();
emit finishedUpdate(); emit finishedUpdate();
} }
// deckbrew.com
/**
* Constructor.
*
* @param _deck deck.
*/
DBPriceUpdater::DBPriceUpdater(const DeckList *_deck)
: AbstractPriceUpdater(_deck)
{
}
/**
* Update the prices of the cards in deckList.
*/
void DBPriceUpdater::updatePrices()
{
QString base = "https://api.deckbrew.com/mtg/cards", q = "";
QStringList cards = deck->getCardList();
muidMap.clear();
urls.clear();
CardInfo * card;
int muid;
SetList sets;
bool bNotFirst=false;
for (int i = 0; i < cards.size(); ++i) {
card = db->getCard(cards[i], false);
sets = card->getSets();
for(int j = 0; j < sets.size(); ++j)
{
muid=card->getMuId(sets[j]->getShortName());
if (!muid) {
continue;
}
//qDebug() << "muid " << muid << " card: " << cards[i] << endl;
if(bNotFirst)
{
q += QString("&m=%1").arg(muid);
} else {
q += QString("?m=%1").arg(muid);
bNotFirst = true;
}
muidMap.insert(muid, cards[i]);
if(q.length() > 240)
{
urls.append(base + q);
bNotFirst=false;
q = "";
}
}
}
if(q.length() > 0)
urls.append(base + q);
requestNext();
}
void DBPriceUpdater::requestNext()
{
if(urls.empty())
return;
QUrl url(urls.takeFirst(), QUrl::TolerantMode);
//qDebug() << "request prices from: " << url.toString() << endl;
QNetworkReply *reply = nam->get(QNetworkRequest(url));
connect(reply, SIGNAL(finished()), this, SLOT(downloadFinished()));
}
/**
* Called when the download of the json file with the prices is finished.
*/
void DBPriceUpdater::downloadFinished()
{
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
bool ok;
QString tmp = QString(reply->readAll());
// Errors are incapsulated in an object, check for them first
QVariantMap resultMap = QtJson::Json::parse(tmp, ok).toMap();
if (!ok) {
QMessageBox::critical(this, tr("Error"), tr("A problem has occured while fetching card prices."));
reply->deleteLater();
if(urls.isEmpty())
{
deleteLater();
emit finishedUpdate();
} else {
requestNext();
}
}
if(resultMap.contains("errors"))
{
QMessageBox::critical(this, tr("Error"), tr("A problem has occured while fetching card prices:") +
"<br/>" +
#if QT_VERSION < 0x050000
Qt::escape(resultMap["errors"].toList().first().toString())
#else
resultMap["errors"].toList().first().toString().toHtmlEscaped()
#endif
);
reply->deleteLater();
if(urls.isEmpty())
{
deleteLater();
emit finishedUpdate();
} else {
requestNext();
}
}
// Good results are a list
QVariantList resultList = QtJson::Json::parse(tmp, ok).toList();
if (!ok) {
QMessageBox::critical(this, tr("Error"), tr("A problem has occured while fetching card prices."));
reply->deleteLater();
if(urls.isEmpty())
{
deleteLater();
emit finishedUpdate();
} else {
requestNext();
}
}
QMap<QString, float> cardsPrice;
QListIterator<QVariant> it(resultList);
while (it.hasNext()) {
QVariantMap cardMap = it.next().toMap();
// get sets list
QList<QVariant> editions = cardMap.value("editions").toList();
foreach (QVariant ed, editions)
{
// retrieve card name "as we know it" from the muid
QVariantMap edition = ed.toMap();
QString set = edition.value("set_id").toString();
int muid = edition.value("multiverse_id").toString().toInt();
if(!muidMap.contains(muid))
continue;
QString name=muidMap.value(muid);
// Prices are in USD cents
float price = edition.value("price").toMap().value("median").toString().toFloat() / 100;
//qDebug() << "card " << name << " set " << set << " price " << price << endl;
/**
* Make sure Masters Edition (MED) isn't the set, as it doesn't
* physically exist. Also check the price to see that the cheapest set
* ends up as the final price.
*/
if (set != "MED" && price > 0 && (!cardsPrice.contains(name) || cardsPrice.value(name) > price))
cardsPrice.insert(name, price);
}
}
InnerDecklistNode *listRoot = deck->getRoot();
for (int i = 0; i < listRoot->size(); i++) {
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
for (int j = 0; j < currentZone->size(); j++) {
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
if (!currentCard)
continue;
float price = cardsPrice[currentCard->getName()];
if(price > 0)
currentCard->setPrice(price);
}
}
reply->deleteLater();
if(urls.isEmpty())
{
deleteLater();
emit finishedUpdate();
} else {
requestNext();
}
}

View file

@ -1,28 +1,57 @@
#ifndef PRICEUPDATER_H #ifndef PRICEUPDATER_H
#define PRICEUPDATER_H #define PRICEUPDATER_H
#include <QNetworkReply> #include <QNetworkAccessManager>
#include "decklist.h" #include "decklist.h"
class QNetworkAccessManager; class QNetworkAccessManager;
// If we don't typedef this, won't compile on OS X < 10.9
typedef QMap<int, QString> MuidStringMap;
/** /**
* Price Updater. * Price Updater.
* *
* @author Marcio Ribeiro <mmr@b1n.org> * @author Marcio Ribeiro <mmr@b1n.org>
*/ */
class PriceUpdater : public QObject class AbstractPriceUpdater : public QWidget
{ {
Q_OBJECT Q_OBJECT
private: public:
enum PriceSource { BLPPriceSource, DBPriceSource };
protected:
const DeckList *deck; const DeckList *deck;
QNetworkAccessManager *nam; QNetworkAccessManager *nam;
signals: signals:
void finishedUpdate(); void finishedUpdate();
private slots: protected slots:
void downloadFinished(); virtual void downloadFinished() = 0;
public: public:
PriceUpdater(const DeckList *deck); AbstractPriceUpdater(const DeckList *deck);
void updatePrices(); virtual void updatePrices() = 0;
};
class BLPPriceUpdater : public AbstractPriceUpdater
{
Q_OBJECT
protected:
virtual void downloadFinished();
public:
BLPPriceUpdater(const DeckList *deck);
virtual void updatePrices();
};
class DBPriceUpdater : public AbstractPriceUpdater
{
Q_OBJECT
protected:
MuidStringMap muidMap;
QList<QString> urls;
protected:
virtual void downloadFinished();
void requestNext();
public:
DBPriceUpdater(const DeckList *deck);
virtual void updatePrices();
}; };
#endif #endif

View file

@ -43,7 +43,7 @@ void ReplayTimelineWidget::setTimeline(const QList<int> &_replayTimeline)
update(); update();
} }
void ReplayTimelineWidget::paintEvent(QPaintEvent *event) void ReplayTimelineWidget::paintEvent(QPaintEvent * /* event */)
{ {
QPainter painter(this); QPainter painter(this);
painter.drawRect(0, 0, width() - 1, height() - 1); painter.drawRect(0, 0, width() - 1, height() - 1);

View file

@ -45,6 +45,7 @@ SettingsCache::SettingsCache()
soundPath = settings->value("sound/path").toString(); soundPath = settings->value("sound/path").toString();
priceTagFeature = settings->value("deckeditor/pricetags", false).toBool(); priceTagFeature = settings->value("deckeditor/pricetags", false).toBool();
priceTagSource = settings->value("deckeditor/pricetagsource", 0).toInt();
ignoreUnregisteredUsers = settings->value("chat/ignore_unregistered", false).toBool(); ignoreUnregisteredUsers = settings->value("chat/ignore_unregistered", false).toBool();
} }
@ -247,6 +248,12 @@ void SettingsCache::setPriceTagFeature(int _priceTagFeature)
emit priceTagFeatureChanged(priceTagFeature); emit priceTagFeatureChanged(priceTagFeature);
} }
void SettingsCache::setPriceTagSource(int _priceTagSource)
{
priceTagSource = _priceTagSource;
settings->setValue("deckeditor/pricetagsource", priceTagSource);
}
void SettingsCache::setIgnoreUnregisteredUsers(bool _ignoreUnregisteredUsers) void SettingsCache::setIgnoreUnregisteredUsers(bool _ignoreUnregisteredUsers)
{ {
ignoreUnregisteredUsers = _ignoreUnregisteredUsers; ignoreUnregisteredUsers = _ignoreUnregisteredUsers;

View file

@ -53,6 +53,7 @@ private:
bool soundEnabled; bool soundEnabled;
QString soundPath; QString soundPath;
bool priceTagFeature; bool priceTagFeature;
int priceTagSource;
bool ignoreUnregisteredUsers; bool ignoreUnregisteredUsers;
QString picUrl; QString picUrl;
QString picUrlHq; QString picUrlHq;
@ -87,6 +88,7 @@ public:
bool getSoundEnabled() const { return soundEnabled; } bool getSoundEnabled() const { return soundEnabled; }
QString getSoundPath() const { return soundPath; } QString getSoundPath() const { return soundPath; }
bool getPriceTagFeature() const { return priceTagFeature; } bool getPriceTagFeature() const { return priceTagFeature; }
int getPriceTagSource() const { return priceTagSource; }
bool getIgnoreUnregisteredUsers() const { return ignoreUnregisteredUsers; } bool getIgnoreUnregisteredUsers() const { return ignoreUnregisteredUsers; }
QString getPicUrl() const { return picUrl; } QString getPicUrl() const { return picUrl; }
QString getPicUrlHq() const { return picUrlHq; } QString getPicUrlHq() const { return picUrlHq; }
@ -121,6 +123,7 @@ public slots:
void setSoundEnabled(int _soundEnabled); void setSoundEnabled(int _soundEnabled);
void setSoundPath(const QString &_soundPath); void setSoundPath(const QString &_soundPath);
void setPriceTagFeature(int _priceTagFeature); void setPriceTagFeature(int _priceTagFeature);
void setPriceTagSource(int _priceTagSource);
void setIgnoreUnregisteredUsers(bool _ignoreUnregisteredUsers); void setIgnoreUnregisteredUsers(bool _ignoreUnregisteredUsers);
void setPicUrl(const QString &_picUrl); void setPicUrl(const QString &_picUrl);
void setPicUrlHq(const QString &_picUrlHq); void setPicUrlHq(const QString &_picUrlHq);

View file

@ -31,6 +31,7 @@ public:
virtual QString getTabText() const = 0; virtual QString getTabText() const = 0;
virtual void retranslateUi() = 0; virtual void retranslateUi() = 0;
virtual void closeRequest() { } virtual void closeRequest() { }
virtual void tabActivated() { }
}; };
#endif #endif

View file

@ -512,7 +512,10 @@ void TabDeckEditor::actPrintDeck()
void TabDeckEditor::actAnalyzeDeck() void TabDeckEditor::actAnalyzeDeck()
{ {
DeckStatsInterface *interface = new DeckStatsInterface(this); // it deletes itself when done DeckStatsInterface *interface = new DeckStatsInterface(
*databaseModel->getDatabase(),
this
); // it deletes itself when done
interface->analyzeDeck(deckModel->getDeckList()); interface->analyzeDeck(deckModel->getDeckList());
} }
@ -643,12 +646,25 @@ void TabDeckEditor::actDecrement()
void TabDeckEditor::setPriceTagFeatureEnabled(int enabled) void TabDeckEditor::setPriceTagFeatureEnabled(int enabled)
{ {
aUpdatePrices->setVisible(enabled); aUpdatePrices->setVisible(enabled);
deckModel->pricesUpdated();
} }
void TabDeckEditor::actUpdatePrices() void TabDeckEditor::actUpdatePrices()
{ {
aUpdatePrices->setDisabled(true); aUpdatePrices->setDisabled(true);
PriceUpdater *up = new PriceUpdater(deckModel->getDeckList()); AbstractPriceUpdater *up;
switch(settingsCache->getPriceTagSource())
{
case AbstractPriceUpdater::DBPriceSource:
up = new DBPriceUpdater(deckModel->getDeckList());
break;
case AbstractPriceUpdater::BLPPriceSource:
default:
up = new BLPPriceUpdater(deckModel->getDeckList());
break;
}
connect(up, SIGNAL(finishedUpdate()), this, SLOT(finishedUpdatingPrices())); connect(up, SIGNAL(finishedUpdate()), this, SLOT(finishedUpdatingPrices()));
up->updatePrices(); up->updatePrices();
} }

View file

@ -255,7 +255,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay)
// Create list: event number -> time [ms] // Create list: event number -> time [ms]
// Distribute simultaneous events evenly across 1 second. // Distribute simultaneous events evenly across 1 second.
int lastEventTimestamp = -1; unsigned int lastEventTimestamp = 0;
const int eventCount = replay->event_list_size(); const int eventCount = replay->event_list_size();
for (int i = 0; i < eventCount; ++i) { for (int i = 0; i < eventCount; ++i) {
int j = i + 1; int j = i + 1;

View file

@ -49,6 +49,12 @@ void TabMessage::retranslateUi()
aLeave->setText(tr("&Leave")); aLeave->setText(tr("&Leave"));
} }
void TabMessage::tabActivated()
{
if(!sayEdit->hasFocus())
sayEdit->setFocus();
}
QString TabMessage::getUserName() const QString TabMessage::getUserName() const
{ {
return QString::fromStdString(otherUserInfo->name()); return QString::fromStdString(otherUserInfo->name());

View file

@ -34,6 +34,7 @@ public:
~TabMessage(); ~TabMessage();
void retranslateUi(); void retranslateUi();
void closeRequest(); void closeRequest();
void tabActivated();
QString getUserName() const; QString getUserName() const;
QString getTabText() const; QString getTabText() const;

View file

@ -202,7 +202,7 @@ void TabReplays::actDownload()
client->sendCommand(pend); client->sendCommand(pend);
} }
void TabReplays::downloadFinished(const Response &r, const CommandContainer &commandContainer, const QVariant &extraData) void TabReplays::downloadFinished(const Response &r, const CommandContainer & /* commandContainer */, const QVariant &extraData)
{ {
if (r.response_code() != Response::RespOk) if (r.response_code() != Response::RespOk)
return; return;

View file

@ -121,6 +121,12 @@ void TabRoom::closeRequest()
actLeaveRoom(); actLeaveRoom();
} }
void TabRoom::tabActivated()
{
if(!sayEdit->hasFocus())
sayEdit->setFocus();
}
QString TabRoom::sanitizeHtml(QString dirty) const QString TabRoom::sanitizeHtml(QString dirty) const
{ {
return dirty return dirty

View file

@ -64,6 +64,7 @@ public:
~TabRoom(); ~TabRoom();
void retranslateUi(); void retranslateUi();
void closeRequest(); void closeRequest();
void tabActivated();
void processRoomEvent(const RoomEvent &event); void processRoomEvent(const RoomEvent &event);
int getRoomId() const { return roomId; } int getRoomId() const { return roomId; }
const QMap<int, QString> &getGameTypes() const { return gameTypes; } const QMap<int, QString> &getGameTypes() const { return gameTypes; }

View file

@ -76,7 +76,7 @@ void CloseButton::paintEvent(QPaintEvent * /*event*/)
} }
TabSupervisor::TabSupervisor(AbstractClient *_client, QWidget *parent) TabSupervisor::TabSupervisor(AbstractClient *_client, QWidget *parent)
: QTabWidget(parent), userInfo(0), client(_client), tabUserLists(0), tabServer(0), tabDeckStorage(0), tabAdmin(0), tabReplays(0) : QTabWidget(parent), userInfo(0), client(_client), tabServer(0), tabUserLists(0), tabDeckStorage(0), tabReplays(0), tabAdmin(0)
{ {
tabChangedIcon = new QIcon(":/resources/icon_tab_changed.svg"); tabChangedIcon = new QIcon(":/resources/icon_tab_changed.svg");
setElideMode(Qt::ElideRight); setElideMode(Qt::ElideRight);
@ -479,6 +479,7 @@ void TabSupervisor::updateCurrent(int index)
tab->setContentsChanged(false); tab->setContentsChanged(false);
} }
emit setMenu(static_cast<Tab *>(widget(index))->getTabMenus()); emit setMenu(static_cast<Tab *>(widget(index))->getTabMenus());
tab->tabActivated();
} else } else
emit setMenu(); emit setMenu();
} }

View file

@ -102,7 +102,7 @@ void UserContextMenu::banUser_dialogFinished()
client->sendCommand(client->prepareModeratorCommand(cmd)); client->sendCommand(client->prepareModeratorCommand(cmd));
} }
void UserContextMenu::showContextMenu(const QPoint &pos, const QString &userName, UserLevelFlags userLevel, int playerId) void UserContextMenu::showContextMenu(const QPoint &pos, const QString &userName, UserLevelFlags userLevel, bool online, int playerId)
{ {
aUserName->setText(userName); aUserName->setText(userName);
@ -132,7 +132,8 @@ void UserContextMenu::showContextMenu(const QPoint &pos, const QString &userName
menu->addAction(aBan); menu->addAction(aBan);
} }
bool anotherUser = userName != QString::fromStdString(tabSupervisor->getUserInfo()->name()); bool anotherUser = userName != QString::fromStdString(tabSupervisor->getUserInfo()->name());
aChat->setEnabled(anotherUser); aDetails->setEnabled(online);
aChat->setEnabled(anotherUser && online);
aShowGames->setEnabled(anotherUser); aShowGames->setEnabled(anotherUser);
aAddToBuddyList->setEnabled(anotherUser); aAddToBuddyList->setEnabled(anotherUser);
aRemoveFromBuddyList->setEnabled(anotherUser); aRemoveFromBuddyList->setEnabled(anotherUser);

View file

@ -36,7 +36,7 @@ private slots:
public: public:
UserContextMenu(const TabSupervisor *_tabSupervisor, QWidget *_parent, TabGame *_game = 0); UserContextMenu(const TabSupervisor *_tabSupervisor, QWidget *_parent, TabGame *_game = 0);
void retranslateUi(); void retranslateUi();
void showContextMenu(const QPoint &pos, const QString &userName, UserLevelFlags userLevel, int playerId = -1); void showContextMenu(const QPoint &pos, const QString &userName, UserLevelFlags userLevel, bool online = true, int playerId = -1);
}; };
#endif #endif

View file

@ -311,8 +311,9 @@ void UserList::userClicked(QTreeWidgetItem *item, int /*column*/)
void UserList::showContextMenu(const QPoint &pos, const QModelIndex &index) void UserList::showContextMenu(const QPoint &pos, const QModelIndex &index)
{ {
const ServerInfo_User &userInfo = static_cast<UserListTWI *>(userTree->topLevelItem(index.row()))->getUserInfo(); const ServerInfo_User &userInfo = static_cast<UserListTWI *>(userTree->topLevelItem(index.row()))->getUserInfo();
bool online = index.sibling(index.row(), 0).data(Qt::UserRole + 1).toBool();
userContextMenu->showContextMenu(pos, QString::fromStdString(userInfo.name()), UserLevelFlags(userInfo.user_level())); userContextMenu->showContextMenu(pos, QString::fromStdString(userInfo.name()), UserLevelFlags(userInfo.user_level()), online);
} }
void UserList::sortItems() void UserList::sortItems()

View file

@ -241,7 +241,7 @@ void MainWindow::loginError(Response::ResponseCode r, QString reasonStr, quint32
{ {
switch (r) { switch (r) {
case Response::RespWrongPassword: case Response::RespWrongPassword:
QMessageBox::critical(this, tr("Error"), tr("Invalid login data.")); QMessageBox::critical(this, tr("Error"), tr("Incorrect username or password. Please check your authentication information and try again."));
break; break;
case Response::RespWouldOverwriteOldSession: case Response::RespWouldOverwriteOldSession:
QMessageBox::critical(this, tr("Error"), tr("There is already an active session using this user name.\nPlease close that session first and re-login.")); QMessageBox::critical(this, tr("Error"), tr("There is already an active session using this user name.\nPlease close that session first and re-login."));

View file

@ -10,26 +10,26 @@
#ifdef QT_GUI_LIB #ifdef QT_GUI_LIB
inline QColor convertColorToQColor(const color &c) inline QColor convertColorToQColor(const color &c)
{ {
return QColor(c.r(), c.g(), c.b()); return QColor(c.r(), c.g(), c.b());
} }
inline color convertQColorToColor(const QColor &c) inline color convertQColorToColor(const QColor &c)
{ {
color result; color result;
result.set_r(c.red()); result.set_r(c.red());
result.set_g(c.green()); result.set_g(c.green());
result.set_b(c.blue()); result.set_b(c.blue());
return result; return result;
} }
#endif #endif
inline color makeColor(int r, int g, int b) inline color makeColor(int r, int g, int b)
{ {
color result; color result;
result.set_r(r); result.set_r(r);
result.set_g(g); result.set_g(g);
result.set_b(b); result.set_b(b);
return result; return result;
} }
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -23,152 +23,175 @@ class InnerDecklistNode;
class SideboardPlan { class SideboardPlan {
private: private:
QString name; QString name;
QList<MoveCard_ToZone> moveList; QList<MoveCard_ToZone> moveList;
public: public:
SideboardPlan(const QString &_name = QString(), const QList<MoveCard_ToZone> &_moveList = QList<MoveCard_ToZone>()); SideboardPlan(const QString &_name = QString(), const QList<MoveCard_ToZone> &_moveList = QList<MoveCard_ToZone>());
bool readElement(QXmlStreamReader *xml); bool readElement(QXmlStreamReader *xml);
void write(QXmlStreamWriter *xml); void write(QXmlStreamWriter *xml);
QString getName() const { return name; } QString getName() const { return name; }
const QList<MoveCard_ToZone> &getMoveList() const { return moveList; } const QList<MoveCard_ToZone> &getMoveList() const { return moveList; }
void setMoveList(const QList<MoveCard_ToZone> &_moveList); void setMoveList(const QList<MoveCard_ToZone> &_moveList);
}; };
enum DeckSortMethod { ByNumber, ByName, ByPrice }; enum DeckSortMethod { ByNumber, ByName, ByPrice };
class AbstractDecklistNode { class AbstractDecklistNode {
protected: protected:
InnerDecklistNode *parent; InnerDecklistNode *parent;
DeckSortMethod sortMethod; DeckSortMethod sortMethod;
public: public:
AbstractDecklistNode(InnerDecklistNode *_parent = 0); AbstractDecklistNode(InnerDecklistNode *_parent = 0);
virtual ~AbstractDecklistNode() { } virtual ~AbstractDecklistNode() { }
virtual void setSortMethod(DeckSortMethod method) { sortMethod = method; } virtual void setSortMethod(DeckSortMethod method) { sortMethod = method; }
virtual QString getName() const = 0; virtual QString getName() const = 0;
InnerDecklistNode *getParent() const { return parent; } InnerDecklistNode *getParent() const { return parent; }
int depth() const; int depth() const;
virtual int height() const = 0; virtual int height() const = 0;
virtual bool compare(AbstractDecklistNode *other) const = 0; virtual bool compare(AbstractDecklistNode *other) const = 0;
virtual bool readElement(QXmlStreamReader *xml) = 0; virtual bool readElement(QXmlStreamReader *xml) = 0;
virtual void writeElement(QXmlStreamWriter *xml) = 0; virtual void writeElement(QXmlStreamWriter *xml) = 0;
}; };
class InnerDecklistNode : public AbstractDecklistNode, public QList<AbstractDecklistNode *> { class InnerDecklistNode : public AbstractDecklistNode, public QList<AbstractDecklistNode *> {
private: private:
QString name; QString name;
class compareFunctor; class compareFunctor;
public: public:
InnerDecklistNode(const QString &_name = QString(), InnerDecklistNode *_parent = 0) : AbstractDecklistNode(_parent), name(_name) { } InnerDecklistNode(const QString &_name = QString(), InnerDecklistNode *_parent = 0) : AbstractDecklistNode(_parent), name(_name) { }
InnerDecklistNode(InnerDecklistNode *other, InnerDecklistNode *_parent = 0); InnerDecklistNode(InnerDecklistNode *other, InnerDecklistNode *_parent = 0);
virtual ~InnerDecklistNode(); virtual ~InnerDecklistNode();
void setSortMethod(DeckSortMethod method); void setSortMethod(DeckSortMethod method);
QString getName() const { return name; } QString getName() const { return name; }
void setName(const QString &_name) { name = _name; } void setName(const QString &_name) { name = _name; }
static QString visibleNameFromName(const QString &_name); static QString visibleNameFromName(const QString &_name);
virtual QString getVisibleName() const; virtual QString getVisibleName() const;
void clearTree(); void clearTree();
AbstractDecklistNode *findChild(const QString &name); AbstractDecklistNode *findChild(const QString &name);
int height() const; int height() const;
int recursiveCount(bool countTotalCards = false) const; int recursiveCount(bool countTotalCards = false) const;
float recursivePrice(bool countTotalCards = false) const; float recursivePrice(bool countTotalCards = false) const;
bool compare(AbstractDecklistNode *other) const; bool compare(AbstractDecklistNode *other) const;
bool compareNumber(AbstractDecklistNode *other) const; bool compareNumber(AbstractDecklistNode *other) const;
bool compareName(AbstractDecklistNode *other) const; bool compareName(AbstractDecklistNode *other) const;
bool comparePrice(AbstractDecklistNode *other) const; bool comparePrice(AbstractDecklistNode *other) const;
QVector<QPair<int, int> > sort(Qt::SortOrder order = Qt::AscendingOrder); QVector<QPair<int, int> > sort(Qt::SortOrder order = Qt::AscendingOrder);
bool readElement(QXmlStreamReader *xml); bool readElement(QXmlStreamReader *xml);
void writeElement(QXmlStreamWriter *xml); void writeElement(QXmlStreamWriter *xml);
}; };
class AbstractDecklistCardNode : public AbstractDecklistNode { class AbstractDecklistCardNode : public AbstractDecklistNode {
public: public:
AbstractDecklistCardNode(InnerDecklistNode *_parent = 0) : AbstractDecklistNode(_parent) { } AbstractDecklistCardNode(InnerDecklistNode *_parent = 0) : AbstractDecklistNode(_parent) { }
virtual int getNumber() const = 0; virtual int getNumber() const = 0;
virtual void setNumber(int _number) = 0; virtual void setNumber(int _number) = 0;
virtual QString getName() const = 0; virtual QString getName() const = 0;
virtual void setName(const QString &_name) = 0; virtual void setName(const QString &_name) = 0;
virtual float getPrice() const = 0; virtual float getPrice() const = 0;
virtual void setPrice(const float _price) = 0; virtual void setPrice(const float _price) = 0;
float getTotalPrice() const { return getNumber() * getPrice(); } float getTotalPrice() const { return getNumber() * getPrice(); }
int height() const { return 0; } int height() const { return 0; }
bool compare(AbstractDecklistNode *other) const; bool compare(AbstractDecklistNode *other) const;
bool compareNumber(AbstractDecklistNode *other) const; bool compareNumber(AbstractDecklistNode *other) const;
bool compareName(AbstractDecklistNode *other) const; bool compareName(AbstractDecklistNode *other) const;
bool compareTotalPrice(AbstractDecklistNode *other) const; bool compareTotalPrice(AbstractDecklistNode *other) const;
bool readElement(QXmlStreamReader *xml); bool readElement(QXmlStreamReader *xml);
void writeElement(QXmlStreamWriter *xml); void writeElement(QXmlStreamWriter *xml);
}; };
class DecklistCardNode : public AbstractDecklistCardNode { class DecklistCardNode : public AbstractDecklistCardNode {
private: private:
QString name; QString name;
int number; int number;
float price; float price;
public: public:
DecklistCardNode(const QString &_name = QString(), int _number = 1, float _price = 0, InnerDecklistNode *_parent = 0) : AbstractDecklistCardNode(_parent), name(_name), number(_number), price(_price) { } DecklistCardNode(const QString &_name = QString(), int _number = 1, float _price = 0, InnerDecklistNode *_parent = 0) : AbstractDecklistCardNode(_parent), name(_name), number(_number), price(_price) { }
DecklistCardNode(const QString &_name = QString(), int _number = 1, InnerDecklistNode *_parent = 0) : AbstractDecklistCardNode(_parent), name(_name), number(_number), price(0) { } DecklistCardNode(const QString &_name = QString(), int _number = 1, InnerDecklistNode *_parent = 0) : AbstractDecklistCardNode(_parent), name(_name), number(_number), price(0) { }
DecklistCardNode(DecklistCardNode *other, InnerDecklistNode *_parent); DecklistCardNode(DecklistCardNode *other, InnerDecklistNode *_parent);
int getNumber() const { return number; } int getNumber() const { return number; }
void setNumber(int _number) { number = _number; } void setNumber(int _number) { number = _number; }
QString getName() const { return name; } QString getName() const { return name; }
void setName(const QString &_name) { name = _name; } void setName(const QString &_name) { name = _name; }
float getPrice() const { return price; } float getPrice() const { return price; }
void setPrice(const float _price) { price = _price; } void setPrice(const float _price) { price = _price; }
}; };
class DeckList : public QObject { class DeckList : public QObject {
Q_OBJECT Q_OBJECT
private: private:
QString name, comments; QString name, comments;
QString deckHash; QString deckHash;
QMap<QString, SideboardPlan *> sideboardPlans; QMap<QString, SideboardPlan *> sideboardPlans;
InnerDecklistNode *root; InnerDecklistNode *root;
void getCardListHelper(InnerDecklistNode *node, QSet<QString> &result) const; void getCardListHelper(InnerDecklistNode *node, QSet<QString> &result) const;
signals: signals:
void deckHashChanged(); void deckHashChanged();
public slots: public slots:
void setName(const QString &_name = QString()) { name = _name; } void setName(const QString &_name = QString()) { name = _name; }
void setComments(const QString &_comments = QString()) { comments = _comments; } void setComments(const QString &_comments = QString()) { comments = _comments; }
public: public:
DeckList(); DeckList();
DeckList(const DeckList &other); DeckList(const DeckList &other);
DeckList(const QString &nativeString); DeckList(const QString &nativeString);
~DeckList(); ~DeckList();
QString getName() const { return name; } QString getName() const { return name; }
QString getComments() const { return comments; } QString getComments() const { return comments; }
QList<MoveCard_ToZone> getCurrentSideboardPlan(); QList<MoveCard_ToZone> getCurrentSideboardPlan();
void setCurrentSideboardPlan(const QList<MoveCard_ToZone> &plan); void setCurrentSideboardPlan(const QList<MoveCard_ToZone> &plan);
const QMap<QString, SideboardPlan *> &getSideboardPlans() const { return sideboardPlans; } const QMap<QString, SideboardPlan *> &getSideboardPlans() const { return sideboardPlans; }
bool readElement(QXmlStreamReader *xml); bool readElement(QXmlStreamReader *xml);
void write(QXmlStreamWriter *xml); void write(QXmlStreamWriter *xml);
bool loadFromXml(QXmlStreamReader *xml); bool loadFromXml(QXmlStreamReader *xml);
bool loadFromString_Native(const QString &nativeString); bool loadFromString_Native(const QString &nativeString);
QString writeToString_Native(); QString writeToString_Native();
bool loadFromFile_Native(QIODevice *device); bool loadFromFile_Native(QIODevice *device);
bool saveToFile_Native(QIODevice *device); bool saveToFile_Native(QIODevice *device);
bool loadFromStream_Plain(QTextStream &stream); bool loadFromStream_Plain(QTextStream &stream);
bool loadFromFile_Plain(QIODevice *device); bool loadFromFile_Plain(QIODevice *device);
bool saveToStream_Plain(QTextStream &stream); bool saveToStream_Plain(QTextStream &stream);
bool saveToFile_Plain(QIODevice *device); bool saveToFile_Plain(QIODevice *device);
QString writeToString_Plain(); QString writeToString_Plain();
void cleanList(); void cleanList();
bool isEmpty() const { return root->isEmpty() && name.isEmpty() && comments.isEmpty() && sideboardPlans.isEmpty(); } bool isEmpty() const { return root->isEmpty() && name.isEmpty() && comments.isEmpty() && sideboardPlans.isEmpty(); }
QStringList getCardList() const; QStringList getCardList() const;
int getSideboardSize() const; int getSideboardSize() const;
QString getDeckHash() const { return deckHash; } QString getDeckHash() const { return deckHash; }
void updateDeckHash(); void updateDeckHash();
InnerDecklistNode *getRoot() const { return root; } InnerDecklistNode *getRoot() const { return root; }
DecklistCardNode *addCard(const QString &cardName, const QString &zoneName); DecklistCardNode *addCard(const QString &cardName, const QString &zoneName);
bool deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNode = 0); bool deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNode = 0);
/**
* Calls a given function object for each card in the deck. It must
* take a InnerDecklistNode* as its first argument and a
* DecklistCardNode* as its second.
*/
template <typename Callback>
void forEachCard(Callback &callback) const {
// Support for this is only possible if the internal structure
// doesn't get more complicated.
for (int i = 0; i < root->size(); i++) {
const InnerDecklistNode *node =
dynamic_cast<InnerDecklistNode *>(root->at(i));
for (int j = 0; j < node->size(); j++) {
const DecklistCardNode *card =
dynamic_cast<DecklistCardNode *>(
node->at(j)
);
callback(node, card);
}
}
}
}; };
#endif #endif

View file

@ -4,10 +4,10 @@
int getPbExtension(const ::google::protobuf::Message &message) int getPbExtension(const ::google::protobuf::Message &message)
{ {
std::vector< const ::google::protobuf::FieldDescriptor * > fieldList; std::vector< const ::google::protobuf::FieldDescriptor * > fieldList;
message.GetReflection()->ListFields(message, &fieldList); message.GetReflection()->ListFields(message, &fieldList);
for (unsigned int j = 0; j < fieldList.size(); ++j) for (unsigned int j = 0; j < fieldList.size(); ++j)
if (fieldList[j]->is_extension()) if (fieldList[j]->is_extension())
return fieldList[j]->number(); return fieldList[j]->number();
return -1; return -1;
} }

View file

@ -2,9 +2,9 @@
#define GET_PB_EXTENSION_H #define GET_PB_EXTENSION_H
namespace google { namespace google {
namespace protobuf { namespace protobuf {
class Message; class Message;
} }
} }
int getPbExtension(const ::google::protobuf::Message &message); int getPbExtension(const ::google::protobuf::Message &message);

View file

@ -4,27 +4,27 @@
QVector<int> RNG_Abstract::makeNumbersVector(int n, int min, int max) QVector<int> RNG_Abstract::makeNumbersVector(int n, int min, int max)
{ {
const int bins = max - min + 1; const int bins = max - min + 1;
QVector<int> result(bins); QVector<int> result(bins);
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
int number = rand(min, max); int number = rand(min, max);
if ((number < min) || (number > max)) if ((number < min) || (number > max))
qDebug() << "rand(" << min << "," << max << ") returned " << number; qDebug() << "rand(" << min << "," << max << ") returned " << number;
else else
result[number - min]++; result[number - min]++;
} }
return result; return result;
} }
double RNG_Abstract::testRandom(const QVector<int> &numbers) const double RNG_Abstract::testRandom(const QVector<int> &numbers) const
{ {
int n = 0; int n = 0;
for (int i = 0; i < numbers.size(); ++i) for (int i = 0; i < numbers.size(); ++i)
n += numbers[i]; n += numbers[i];
double expected = (double) n / (double) numbers.size(); double expected = (double) n / (double) numbers.size();
double chisq = 0; double chisq = 0;
for (int i = 0; i < numbers.size(); ++i) for (int i = 0; i < numbers.size(); ++i)
chisq += ((double) numbers[i] - expected) * ((double) numbers[i] - expected) / expected; chisq += ((double) numbers[i] - expected) * ((double) numbers[i] - expected) / expected;
return chisq; return chisq;
} }

View file

@ -5,12 +5,12 @@
#include <QVector> #include <QVector>
class RNG_Abstract : public QObject { class RNG_Abstract : public QObject {
Q_OBJECT Q_OBJECT
public: public:
RNG_Abstract(QObject *parent = 0) : QObject(parent) { } RNG_Abstract(QObject *parent = 0) : QObject(parent) { }
virtual unsigned int rand(int min, int max) = 0; virtual unsigned int rand(int min, int max) = 0;
QVector<int> makeNumbersVector(int n, int min, int max); QVector<int> makeNumbersVector(int n, int min, int max);
double testRandom(const QVector<int> &numbers) const; double testRandom(const QVector<int> &numbers) const;
}; };
extern RNG_Abstract *rng; extern RNG_Abstract *rng;

View file

@ -11,10 +11,10 @@
#endif #endif
RNG_SFMT::RNG_SFMT(QObject *parent) RNG_SFMT::RNG_SFMT(QObject *parent)
: RNG_Abstract(parent) : RNG_Abstract(parent)
{ {
// initialize the random number generator with a 32bit integer seed (timestamp) // initialize the random number generator with a 32bit integer seed (timestamp)
sfmt_init_gen_rand(&sfmt, QDateTime::currentDateTime().toTime_t()); sfmt_init_gen_rand(&sfmt, QDateTime::currentDateTime().toTime_t());
} }
/** /**
@ -32,11 +32,11 @@ unsigned int RNG_SFMT::rand(int min, int max) {
* There has been no use for negative random numbers with rand() though, so it's treated as error. * There has been no use for negative random numbers with rand() though, so it's treated as error.
*/ */
if(min < 0) { if(min < 0) {
throw std::invalid_argument( throw std::invalid_argument(
QString("Invalid bounds for RNG: Got min " + QString("Invalid bounds for RNG: Got min " +
QString::number(min) + " < 0!\n").toStdString()); QString::number(min) + " < 0!\n").toStdString());
// at this point, the method exits. No return value is needed, because // at this point, the method exits. No return value is needed, because
// basically the exception itself is returned. // basically the exception itself is returned.
} }
// For complete fairness and equal timing, this should be a roll, but let's skip it anyway // For complete fairness and equal timing, this should be a roll, but let's skip it anyway
@ -99,38 +99,38 @@ unsigned int RNG_SFMT::rand(int min, int max) {
*/ */
unsigned int RNG_SFMT::cdf(unsigned int min, unsigned int max) unsigned int RNG_SFMT::cdf(unsigned int min, unsigned int max)
{ {
// This all makes no sense if min > max, which should never happen. // This all makes no sense if min > max, which should never happen.
if(min > max) { if(min > max) {
throw std::invalid_argument( throw std::invalid_argument(
QString("Invalid bounds for RNG: min > max! Values were: min = " + QString("Invalid bounds for RNG: min > max! Values were: min = " +
QString::number(min) + ", max = " + QString::number(min) + ", max = " +
QString::number(max)).toStdString()); QString::number(max)).toStdString());
// at this point, the method exits. No return value is needed, because // at this point, the method exits. No return value is needed, because
// basically the exception itself is returned. // basically the exception itself is returned.
} }
// First compute the diameter (aka size, length) of the [min, max] interval // First compute the diameter (aka size, length) of the [min, max] interval
const unsigned int diameter = max - min + 1; const unsigned int diameter = max - min + 1;
// Compute how many buckets (each in size of the diameter) will fit into the // Compute how many buckets (each in size of the diameter) will fit into the
// universe. // universe.
// If the division has a remainder, the result is floored automatically. // If the division has a remainder, the result is floored automatically.
const uint64_t buckets = UINT64_MAX / diameter; const uint64_t buckets = UINT64_MAX / diameter;
// Compute the last valid random number. All numbers beyond have to be ignored. // Compute the last valid random number. All numbers beyond have to be ignored.
// If there was no remainder in the previous step, limit is equal to UINT64_MAX. // If there was no remainder in the previous step, limit is equal to UINT64_MAX.
const uint64_t limit = diameter * buckets; const uint64_t limit = diameter * buckets;
uint64_t rand; uint64_t rand;
// To make the random number generation thread-safe, a mutex is created around // To make the random number generation thread-safe, a mutex is created around
// the generation. Outside of the loop of course, to avoid lock/unlock overhead. // the generation. Outside of the loop of course, to avoid lock/unlock overhead.
mutex.lock(); mutex.lock();
do { do {
rand = sfmt_genrand_uint64(&sfmt); rand = sfmt_genrand_uint64(&sfmt);
} while (rand >= limit); } while (rand >= limit);
mutex.unlock(); mutex.unlock();
// Now determine the bucket containing the SFMT() random number and after adding // Now determine the bucket containing the SFMT() random number and after adding
// the lower bound, a random number from [min, max] can be returned. // the lower bound, a random number from [min, max] can be returned.
return (unsigned int) (rand / buckets + min); return (unsigned int) (rand / buckets + min);
} }

View file

@ -26,15 +26,15 @@
*/ */
class RNG_SFMT : public RNG_Abstract { class RNG_SFMT : public RNG_Abstract {
Q_OBJECT Q_OBJECT
private: private:
QMutex mutex; QMutex mutex;
sfmt_t sfmt; sfmt_t sfmt;
// The discrete cumulative distribution function for the RNG // The discrete cumulative distribution function for the RNG
unsigned int cdf(unsigned int min, unsigned int max); unsigned int cdf(unsigned int min, unsigned int max);
public: public:
RNG_SFMT(QObject *parent = 0); RNG_SFMT(QObject *parent = 0);
unsigned int rand(int min, int max); unsigned int rand(int min, int max);
}; };
#endif #endif

View file

@ -36,18 +36,18 @@
#include <QDebug> #include <QDebug>
Server::Server(bool _threaded, QObject *parent) Server::Server(bool _threaded, QObject *parent)
: QObject(parent), threaded(_threaded), nextLocalGameId(0) : QObject(parent), threaded(_threaded), nextLocalGameId(0)
{ {
qRegisterMetaType<ServerInfo_Game>("ServerInfo_Game"); qRegisterMetaType<ServerInfo_Game>("ServerInfo_Game");
qRegisterMetaType<ServerInfo_Room>("ServerInfo_Room"); qRegisterMetaType<ServerInfo_Room>("ServerInfo_Room");
qRegisterMetaType<ServerInfo_User>("ServerInfo_User"); qRegisterMetaType<ServerInfo_User>("ServerInfo_User");
qRegisterMetaType<CommandContainer>("CommandContainer"); qRegisterMetaType<CommandContainer>("CommandContainer");
qRegisterMetaType<Response>("Response"); qRegisterMetaType<Response>("Response");
qRegisterMetaType<GameEventContainer>("GameEventContainer"); qRegisterMetaType<GameEventContainer>("GameEventContainer");
qRegisterMetaType<IslMessage>("IslMessage"); qRegisterMetaType<IslMessage>("IslMessage");
qRegisterMetaType<Command_JoinGame>("Command_JoinGame"); qRegisterMetaType<Command_JoinGame>("Command_JoinGame");
connect(this, SIGNAL(sigSendIslMessage(IslMessage, int)), this, SLOT(doSendIslMessage(IslMessage, int)), Qt::QueuedConnection); connect(this, SIGNAL(sigSendIslMessage(IslMessage, int)), this, SLOT(doSendIslMessage(IslMessage, int)), Qt::QueuedConnection);
} }
Server::~Server() Server::~Server()
@ -56,532 +56,532 @@ Server::~Server()
void Server::prepareDestroy() void Server::prepareDestroy()
{ {
// dirty :( // dirty :(
if (threaded) { if (threaded) {
clientsLock.lockForRead(); clientsLock.lockForRead();
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
QMetaObject::invokeMethod(clients.at(i), "prepareDestroy", Qt::QueuedConnection); QMetaObject::invokeMethod(clients.at(i), "prepareDestroy", Qt::QueuedConnection);
clientsLock.unlock(); clientsLock.unlock();
bool done = false; bool done = false;
class SleeperThread : public QThread class SleeperThread : public QThread
{ {
public: public:
static void msleep(unsigned long msecs) { QThread::usleep(msecs); } static void msleep(unsigned long msecs) { QThread::usleep(msecs); }
}; };
do { do {
SleeperThread::msleep(10); SleeperThread::msleep(10);
clientsLock.lockForRead(); clientsLock.lockForRead();
if (clients.isEmpty()) if (clients.isEmpty())
done = true; done = true;
clientsLock.unlock(); clientsLock.unlock();
} while (!done); } while (!done);
} else { } else {
// no locking is needed in unthreaded mode // no locking is needed in unthreaded mode
while (!clients.isEmpty()) while (!clients.isEmpty())
clients.first()->prepareDestroy(); clients.first()->prepareDestroy();
} }
roomsLock.lockForWrite(); roomsLock.lockForWrite();
QMapIterator<int, Server_Room *> roomIterator(rooms); QMapIterator<int, Server_Room *> roomIterator(rooms);
while (roomIterator.hasNext()) while (roomIterator.hasNext())
delete roomIterator.next().value(); delete roomIterator.next().value();
rooms.clear(); rooms.clear();
roomsLock.unlock(); roomsLock.unlock();
} }
void Server::setDatabaseInterface(Server_DatabaseInterface *_databaseInterface) void Server::setDatabaseInterface(Server_DatabaseInterface *_databaseInterface)
{ {
connect(this, SIGNAL(endSession(qint64)), _databaseInterface, SLOT(endSession(qint64))); connect(this, SIGNAL(endSession(qint64)), _databaseInterface, SLOT(endSession(qint64)));
databaseInterfaces.insert(QThread::currentThread(), _databaseInterface); databaseInterfaces.insert(QThread::currentThread(), _databaseInterface);
} }
Server_DatabaseInterface *Server::getDatabaseInterface() const Server_DatabaseInterface *Server::getDatabaseInterface() const
{ {
return databaseInterfaces.value(QThread::currentThread()); return databaseInterfaces.value(QThread::currentThread());
} }
AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reasonStr, int &secondsLeft) AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reasonStr, int &secondsLeft)
{ {
if (name.size() > 35) if (name.size() > 35)
name = name.left(35); name = name.left(35);
Server_DatabaseInterface *databaseInterface = getDatabaseInterface(); Server_DatabaseInterface *databaseInterface = getDatabaseInterface();
QWriteLocker locker(&clientsLock); QWriteLocker locker(&clientsLock);
AuthenticationResult authState = databaseInterface->checkUserPassword(session, name, password, reasonStr, secondsLeft); AuthenticationResult authState = databaseInterface->checkUserPassword(session, name, password, reasonStr, secondsLeft);
if ((authState == NotLoggedIn) || (authState == UserIsBanned || authState == UsernameInvalid)) if ((authState == NotLoggedIn) || (authState == UserIsBanned || authState == UsernameInvalid))
return authState; return authState;
ServerInfo_User data = databaseInterface->getUserData(name, true); ServerInfo_User data = databaseInterface->getUserData(name, true);
data.set_address(session->getAddress().toStdString()); data.set_address(session->getAddress().toStdString());
name = QString::fromStdString(data.name()); // Compensate for case indifference name = QString::fromStdString(data.name()); // Compensate for case indifference
databaseInterface->lockSessionTables(); databaseInterface->lockSessionTables();
if (authState == PasswordRight) { if (authState == PasswordRight) {
if (users.contains(name) || databaseInterface->userSessionExists(name)) { if (users.contains(name) || databaseInterface->userSessionExists(name)) {
qDebug("Login denied: would overwrite old session"); qDebug("Login denied: would overwrite old session");
databaseInterface->unlockSessionTables(); databaseInterface->unlockSessionTables();
return WouldOverwriteOldSession; return WouldOverwriteOldSession;
} }
} else if (authState == UnknownUser) { } else if (authState == UnknownUser) {
// Change user name so that no two users have the same names, // Change user name so that no two users have the same names,
// don't interfere with registered user names though. // don't interfere with registered user names though.
QString tempName = name; QString tempName = name;
int i = 0; int i = 0;
while (users.contains(tempName) || databaseInterface->userExists(tempName) || databaseInterface->userSessionExists(tempName)) while (users.contains(tempName) || databaseInterface->userExists(tempName) || databaseInterface->userSessionExists(tempName))
tempName = name + "_" + QString::number(++i); tempName = name + "_" + QString::number(++i);
name = tempName; name = tempName;
data.set_name(name.toStdString()); data.set_name(name.toStdString());
} }
users.insert(name, session); users.insert(name, session);
qDebug() << "Server::loginUser:" << session << "name=" << name; qDebug() << "Server::loginUser:" << session << "name=" << name;
data.set_session_id(databaseInterface->startSession(name, session->getAddress())); data.set_session_id(databaseInterface->startSession(name, session->getAddress()));
databaseInterface->unlockSessionTables(); databaseInterface->unlockSessionTables();
usersBySessionId.insert(data.session_id(), session); usersBySessionId.insert(data.session_id(), session);
qDebug() << "session id:" << data.session_id(); qDebug() << "session id:" << data.session_id();
session->setUserInfo(data); session->setUserInfo(data);
Event_UserJoined event; Event_UserJoined event;
event.mutable_user_info()->CopyFrom(session->copyUserInfo(false)); event.mutable_user_info()->CopyFrom(session->copyUserInfo(false));
SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event);
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
if (clients[i]->getAcceptsUserListChanges()) if (clients[i]->getAcceptsUserListChanges())
clients[i]->sendProtocolItem(*se); clients[i]->sendProtocolItem(*se);
delete se; delete se;
event.mutable_user_info()->CopyFrom(session->copyUserInfo(true, true, true)); event.mutable_user_info()->CopyFrom(session->copyUserInfo(true, true, true));
locker.unlock(); locker.unlock();
se = Server_ProtocolHandler::prepareSessionEvent(event); se = Server_ProtocolHandler::prepareSessionEvent(event);
sendIsl_SessionEvent(*se); sendIsl_SessionEvent(*se);
delete se; delete se;
return authState; return authState;
} }
void Server::addPersistentPlayer(const QString &userName, int roomId, int gameId, int playerId) void Server::addPersistentPlayer(const QString &userName, int roomId, int gameId, int playerId)
{ {
QWriteLocker locker(&persistentPlayersLock); QWriteLocker locker(&persistentPlayersLock);
persistentPlayers.insert(userName, PlayerReference(roomId, gameId, playerId)); persistentPlayers.insert(userName, PlayerReference(roomId, gameId, playerId));
} }
void Server::removePersistentPlayer(const QString &userName, int roomId, int gameId, int playerId) void Server::removePersistentPlayer(const QString &userName, int roomId, int gameId, int playerId)
{ {
QWriteLocker locker(&persistentPlayersLock); QWriteLocker locker(&persistentPlayersLock);
persistentPlayers.remove(userName, PlayerReference(roomId, gameId, playerId)); persistentPlayers.remove(userName, PlayerReference(roomId, gameId, playerId));
} }
QList<PlayerReference> Server::getPersistentPlayerReferences(const QString &userName) const QList<PlayerReference> Server::getPersistentPlayerReferences(const QString &userName) const
{ {
QReadLocker locker(&persistentPlayersLock); QReadLocker locker(&persistentPlayersLock);
return persistentPlayers.values(userName); return persistentPlayers.values(userName);
} }
Server_AbstractUserInterface *Server::findUser(const QString &userName) const Server_AbstractUserInterface *Server::findUser(const QString &userName) const
{ {
// Call this only with clientsLock set. // Call this only with clientsLock set.
Server_AbstractUserInterface *userHandler = users.value(userName); Server_AbstractUserInterface *userHandler = users.value(userName);
if (userHandler) if (userHandler)
return userHandler; return userHandler;
else else
return externalUsers.value(userName); return externalUsers.value(userName);
} }
void Server::addClient(Server_ProtocolHandler *client) void Server::addClient(Server_ProtocolHandler *client)
{ {
QWriteLocker locker(&clientsLock); QWriteLocker locker(&clientsLock);
clients << client; clients << client;
} }
void Server::removeClient(Server_ProtocolHandler *client) void Server::removeClient(Server_ProtocolHandler *client)
{ {
QWriteLocker locker(&clientsLock); QWriteLocker locker(&clientsLock);
clients.removeAt(clients.indexOf(client)); clients.removeAt(clients.indexOf(client));
ServerInfo_User *data = client->getUserInfo(); ServerInfo_User *data = client->getUserInfo();
if (data) { if (data) {
Event_UserLeft event; Event_UserLeft event;
event.set_name(data->name()); event.set_name(data->name());
SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event);
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
if (clients[i]->getAcceptsUserListChanges()) if (clients[i]->getAcceptsUserListChanges())
clients[i]->sendProtocolItem(*se); clients[i]->sendProtocolItem(*se);
sendIsl_SessionEvent(*se); sendIsl_SessionEvent(*se);
delete se; delete se;
users.remove(QString::fromStdString(data->name())); users.remove(QString::fromStdString(data->name()));
qDebug() << "Server::removeClient: name=" << QString::fromStdString(data->name()); qDebug() << "Server::removeClient: name=" << QString::fromStdString(data->name());
if (data->has_session_id()) { if (data->has_session_id()) {
const qint64 sessionId = data->session_id(); const qint64 sessionId = data->session_id();
usersBySessionId.remove(sessionId); usersBySessionId.remove(sessionId);
emit endSession(sessionId); emit endSession(sessionId);
qDebug() << "closed session id:" << sessionId; qDebug() << "closed session id:" << sessionId;
} }
} }
qDebug() << "Server::removeClient: removed" << (void *) client << ";" << clients.size() << "clients; " << users.size() << "users left"; qDebug() << "Server::removeClient: removed" << (void *) client << ";" << clients.size() << "clients; " << users.size() << "users left";
} }
void Server::externalUserJoined(const ServerInfo_User &userInfo) void Server::externalUserJoined(const ServerInfo_User &userInfo)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
clientsLock.lockForWrite(); clientsLock.lockForWrite();
Server_RemoteUserInterface *newUser = new Server_RemoteUserInterface(this, ServerInfo_User_Container(userInfo)); Server_RemoteUserInterface *newUser = new Server_RemoteUserInterface(this, ServerInfo_User_Container(userInfo));
externalUsers.insert(QString::fromStdString(userInfo.name()), newUser); externalUsers.insert(QString::fromStdString(userInfo.name()), newUser);
externalUsersBySessionId.insert(userInfo.session_id(), newUser); externalUsersBySessionId.insert(userInfo.session_id(), newUser);
Event_UserJoined event; Event_UserJoined event;
event.mutable_user_info()->CopyFrom(userInfo); event.mutable_user_info()->CopyFrom(userInfo);
SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event);
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
if (clients[i]->getAcceptsUserListChanges()) if (clients[i]->getAcceptsUserListChanges())
clients[i]->sendProtocolItem(*se); clients[i]->sendProtocolItem(*se);
delete se; delete se;
clientsLock.unlock(); clientsLock.unlock();
ResponseContainer rc(-1); ResponseContainer rc(-1);
newUser->joinPersistentGames(rc); newUser->joinPersistentGames(rc);
newUser->sendResponseContainer(rc, Response::RespNothing); newUser->sendResponseContainer(rc, Response::RespNothing);
} }
void Server::externalUserLeft(const QString &userName) void Server::externalUserLeft(const QString &userName)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
clientsLock.lockForWrite(); clientsLock.lockForWrite();
Server_AbstractUserInterface *user = externalUsers.take(userName); Server_AbstractUserInterface *user = externalUsers.take(userName);
externalUsersBySessionId.remove(user->getUserInfo()->session_id()); externalUsersBySessionId.remove(user->getUserInfo()->session_id());
clientsLock.unlock(); clientsLock.unlock();
QMap<int, QPair<int, int> > userGames(user->getGames()); QMap<int, QPair<int, int> > userGames(user->getGames());
QMapIterator<int, QPair<int, int> > userGamesIterator(userGames); QMapIterator<int, QPair<int, int> > userGamesIterator(userGames);
roomsLock.lockForRead(); roomsLock.lockForRead();
while (userGamesIterator.hasNext()) { while (userGamesIterator.hasNext()) {
userGamesIterator.next(); userGamesIterator.next();
Server_Room *room = rooms.value(userGamesIterator.value().first); Server_Room *room = rooms.value(userGamesIterator.value().first);
if (!room) if (!room)
continue; continue;
QReadLocker roomGamesLocker(&room->gamesLock); QReadLocker roomGamesLocker(&room->gamesLock);
Server_Game *game = room->getGames().value(userGamesIterator.key()); Server_Game *game = room->getGames().value(userGamesIterator.key());
if (!game) if (!game)
continue; continue;
QMutexLocker gameLocker(&game->gameMutex); QMutexLocker gameLocker(&game->gameMutex);
Server_Player *player = game->getPlayers().value(userGamesIterator.value().second); Server_Player *player = game->getPlayers().value(userGamesIterator.value().second);
if (!player) if (!player)
continue; continue;
player->disconnectClient(); player->disconnectClient();
} }
roomsLock.unlock(); roomsLock.unlock();
delete user; delete user;
Event_UserLeft event; Event_UserLeft event;
event.set_name(userName.toStdString()); event.set_name(userName.toStdString());
SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event);
clientsLock.lockForRead(); clientsLock.lockForRead();
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
if (clients[i]->getAcceptsUserListChanges()) if (clients[i]->getAcceptsUserListChanges())
clients[i]->sendProtocolItem(*se); clients[i]->sendProtocolItem(*se);
clientsLock.unlock(); clientsLock.unlock();
delete se; delete se;
} }
void Server::externalRoomUserJoined(int roomId, const ServerInfo_User &userInfo) void Server::externalRoomUserJoined(int roomId, const ServerInfo_User &userInfo)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
QReadLocker locker(&roomsLock); QReadLocker locker(&roomsLock);
Server_Room *room = rooms.value(roomId); Server_Room *room = rooms.value(roomId);
if (!room) { if (!room) {
qDebug() << "externalRoomUserJoined: room id=" << roomId << "not found"; qDebug() << "externalRoomUserJoined: room id=" << roomId << "not found";
return; return;
} }
room->addExternalUser(userInfo); room->addExternalUser(userInfo);
} }
void Server::externalRoomUserLeft(int roomId, const QString &userName) void Server::externalRoomUserLeft(int roomId, const QString &userName)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
QReadLocker locker(&roomsLock); QReadLocker locker(&roomsLock);
Server_Room *room = rooms.value(roomId); Server_Room *room = rooms.value(roomId);
if (!room) { if (!room) {
qDebug() << "externalRoomUserLeft: room id=" << roomId << "not found"; qDebug() << "externalRoomUserLeft: room id=" << roomId << "not found";
return; return;
} }
room->removeExternalUser(userName); room->removeExternalUser(userName);
} }
void Server::externalRoomSay(int roomId, const QString &userName, const QString &message) void Server::externalRoomSay(int roomId, const QString &userName, const QString &message)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
QReadLocker locker(&roomsLock); QReadLocker locker(&roomsLock);
Server_Room *room = rooms.value(roomId); Server_Room *room = rooms.value(roomId);
if (!room) { if (!room) {
qDebug() << "externalRoomSay: room id=" << roomId << "not found"; qDebug() << "externalRoomSay: room id=" << roomId << "not found";
return; return;
} }
room->say(userName, message, false); room->say(userName, message, false);
} }
void Server::externalRoomGameListChanged(int roomId, const ServerInfo_Game &gameInfo) void Server::externalRoomGameListChanged(int roomId, const ServerInfo_Game &gameInfo)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
QReadLocker locker(&roomsLock); QReadLocker locker(&roomsLock);
Server_Room *room = rooms.value(roomId); Server_Room *room = rooms.value(roomId);
if (!room) { if (!room) {
qDebug() << "externalRoomGameListChanged: room id=" << roomId << "not found"; qDebug() << "externalRoomGameListChanged: room id=" << roomId << "not found";
return; return;
} }
room->updateExternalGameList(gameInfo); room->updateExternalGameList(gameInfo);
} }
void Server::externalJoinGameCommandReceived(const Command_JoinGame &cmd, int cmdId, int roomId, int serverId, qint64 sessionId) void Server::externalJoinGameCommandReceived(const Command_JoinGame &cmd, int cmdId, int roomId, int serverId, qint64 sessionId)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
try { try {
QReadLocker roomsLocker(&roomsLock); QReadLocker roomsLocker(&roomsLock);
QReadLocker clientsLocker(&clientsLock); QReadLocker clientsLocker(&clientsLock);
Server_Room *room = rooms.value(roomId); Server_Room *room = rooms.value(roomId);
if (!room) { if (!room) {
qDebug() << "externalJoinGameCommandReceived: room id=" << roomId << "not found"; qDebug() << "externalJoinGameCommandReceived: room id=" << roomId << "not found";
throw Response::RespNotInRoom; throw Response::RespNotInRoom;
} }
Server_AbstractUserInterface *userInterface = externalUsersBySessionId.value(sessionId); Server_AbstractUserInterface *userInterface = externalUsersBySessionId.value(sessionId);
if (!userInterface) { if (!userInterface) {
qDebug() << "externalJoinGameCommandReceived: session id=" << sessionId << "not found"; qDebug() << "externalJoinGameCommandReceived: session id=" << sessionId << "not found";
throw Response::RespNotInRoom; throw Response::RespNotInRoom;
} }
ResponseContainer responseContainer(cmdId); ResponseContainer responseContainer(cmdId);
Response::ResponseCode responseCode = room->processJoinGameCommand(cmd, responseContainer, userInterface); Response::ResponseCode responseCode = room->processJoinGameCommand(cmd, responseContainer, userInterface);
userInterface->sendResponseContainer(responseContainer, responseCode); userInterface->sendResponseContainer(responseContainer, responseCode);
} catch (Response::ResponseCode code) { } catch (Response::ResponseCode code) {
Response response; Response response;
response.set_cmd_id(cmdId); response.set_cmd_id(cmdId);
response.set_response_code(code); response.set_response_code(code);
sendIsl_Response(response, serverId, sessionId); sendIsl_Response(response, serverId, sessionId);
} }
} }
void Server::externalGameCommandContainerReceived(const CommandContainer &cont, int playerId, int serverId, qint64 sessionId) void Server::externalGameCommandContainerReceived(const CommandContainer &cont, int playerId, int serverId, qint64 sessionId)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
try { try {
ResponseContainer responseContainer(cont.cmd_id()); ResponseContainer responseContainer(cont.cmd_id());
Response::ResponseCode finalResponseCode = Response::RespOk; Response::ResponseCode finalResponseCode = Response::RespOk;
QReadLocker roomsLocker(&roomsLock); QReadLocker roomsLocker(&roomsLock);
Server_Room *room = rooms.value(cont.room_id()); Server_Room *room = rooms.value(cont.room_id());
if (!room) { if (!room) {
qDebug() << "externalGameCommandContainerReceived: room id=" << cont.room_id() << "not found"; qDebug() << "externalGameCommandContainerReceived: room id=" << cont.room_id() << "not found";
throw Response::RespNotInRoom; throw Response::RespNotInRoom;
} }
QReadLocker roomGamesLocker(&room->gamesLock); QReadLocker roomGamesLocker(&room->gamesLock);
Server_Game *game = room->getGames().value(cont.game_id()); Server_Game *game = room->getGames().value(cont.game_id());
if (!game) { if (!game) {
qDebug() << "externalGameCommandContainerReceived: game id=" << cont.game_id() << "not found"; qDebug() << "externalGameCommandContainerReceived: game id=" << cont.game_id() << "not found";
throw Response::RespNotInRoom; throw Response::RespNotInRoom;
} }
QMutexLocker gameLocker(&game->gameMutex); QMutexLocker gameLocker(&game->gameMutex);
Server_Player *player = game->getPlayers().value(playerId); Server_Player *player = game->getPlayers().value(playerId);
if (!player) { if (!player) {
qDebug() << "externalGameCommandContainerReceived: player id=" << playerId << "not found"; qDebug() << "externalGameCommandContainerReceived: player id=" << playerId << "not found";
throw Response::RespNotInRoom; throw Response::RespNotInRoom;
} }
GameEventStorage ges; GameEventStorage ges;
for (int i = cont.game_command_size() - 1; i >= 0; --i) { for (int i = cont.game_command_size() - 1; i >= 0; --i) {
const GameCommand &sc = cont.game_command(i); const GameCommand &sc = cont.game_command(i);
qDebug() << "[ISL]" << QString::fromStdString(sc.ShortDebugString()); qDebug() << "[ISL]" << QString::fromStdString(sc.ShortDebugString());
Response::ResponseCode resp = player->processGameCommand(sc, responseContainer, ges); Response::ResponseCode resp = player->processGameCommand(sc, responseContainer, ges);
if (resp != Response::RespOk) if (resp != Response::RespOk)
finalResponseCode = resp; finalResponseCode = resp;
} }
ges.sendToGame(game); ges.sendToGame(game);
if (finalResponseCode != Response::RespNothing) { if (finalResponseCode != Response::RespNothing) {
player->playerMutex.lock(); player->playerMutex.lock();
player->getUserInterface()->sendResponseContainer(responseContainer, finalResponseCode); player->getUserInterface()->sendResponseContainer(responseContainer, finalResponseCode);
player->playerMutex.unlock(); player->playerMutex.unlock();
} }
} catch (Response::ResponseCode code) { } catch (Response::ResponseCode code) {
Response response; Response response;
response.set_cmd_id(cont.cmd_id()); response.set_cmd_id(cont.cmd_id());
response.set_response_code(code); response.set_response_code(code);
sendIsl_Response(response, serverId, sessionId); sendIsl_Response(response, serverId, sessionId);
} }
} }
void Server::externalGameEventContainerReceived(const GameEventContainer &cont, qint64 sessionId) void Server::externalGameEventContainerReceived(const GameEventContainer &cont, qint64 sessionId)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
QReadLocker usersLocker(&clientsLock); QReadLocker usersLocker(&clientsLock);
Server_ProtocolHandler *client = usersBySessionId.value(sessionId); Server_ProtocolHandler *client = usersBySessionId.value(sessionId);
if (!client) { if (!client) {
qDebug() << "externalGameEventContainerReceived: session" << sessionId << "not found"; qDebug() << "externalGameEventContainerReceived: session" << sessionId << "not found";
return; return;
} }
client->sendProtocolItem(cont); client->sendProtocolItem(cont);
} }
void Server::externalResponseReceived(const Response &resp, qint64 sessionId) void Server::externalResponseReceived(const Response &resp, qint64 sessionId)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
QReadLocker usersLocker(&clientsLock); QReadLocker usersLocker(&clientsLock);
Server_ProtocolHandler *client = usersBySessionId.value(sessionId); Server_ProtocolHandler *client = usersBySessionId.value(sessionId);
if (!client) { if (!client) {
qDebug() << "externalResponseReceived: session" << sessionId << "not found"; qDebug() << "externalResponseReceived: session" << sessionId << "not found";
return; return;
} }
client->sendProtocolItem(resp); client->sendProtocolItem(resp);
} }
void Server::broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl) void Server::broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
Event_ListRooms event; Event_ListRooms event;
event.add_room_list()->CopyFrom(roomInfo); event.add_room_list()->CopyFrom(roomInfo);
SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event);
clientsLock.lockForRead(); clientsLock.lockForRead();
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
if (clients[i]->getAcceptsRoomListChanges()) if (clients[i]->getAcceptsRoomListChanges())
clients[i]->sendProtocolItem(*se); clients[i]->sendProtocolItem(*se);
clientsLock.unlock(); clientsLock.unlock();
if (sendToIsl) if (sendToIsl)
sendIsl_SessionEvent(*se); sendIsl_SessionEvent(*se);
delete se; delete se;
} }
void Server::addRoom(Server_Room *newRoom) void Server::addRoom(Server_Room *newRoom)
{ {
QWriteLocker locker(&roomsLock); QWriteLocker locker(&roomsLock);
qDebug() << "Adding room: ID=" << newRoom->getId() << "name=" << newRoom->getName(); qDebug() << "Adding room: ID=" << newRoom->getId() << "name=" << newRoom->getName();
rooms.insert(newRoom->getId(), newRoom); rooms.insert(newRoom->getId(), newRoom);
connect(newRoom, SIGNAL(roomInfoChanged(ServerInfo_Room)), this, SLOT(broadcastRoomUpdate(const ServerInfo_Room &)), Qt::QueuedConnection); connect(newRoom, SIGNAL(roomInfoChanged(ServerInfo_Room)), this, SLOT(broadcastRoomUpdate(const ServerInfo_Room &)), Qt::QueuedConnection);
} }
int Server::getUsersCount() const int Server::getUsersCount() const
{ {
QReadLocker locker(&clientsLock); QReadLocker locker(&clientsLock);
return users.size(); return users.size();
} }
int Server::getGamesCount() const int Server::getGamesCount() const
{ {
int result = 0; int result = 0;
QReadLocker locker(&roomsLock); QReadLocker locker(&roomsLock);
QMapIterator<int, Server_Room *> roomIterator(rooms); QMapIterator<int, Server_Room *> roomIterator(rooms);
while (roomIterator.hasNext()) { while (roomIterator.hasNext()) {
Server_Room *room = roomIterator.next().value(); Server_Room *room = roomIterator.next().value();
QReadLocker roomLocker(&room->gamesLock); QReadLocker roomLocker(&room->gamesLock);
result += room->getGames().size(); result += room->getGames().size();
} }
return result; return result;
} }
void Server::sendIsl_Response(const Response &item, int serverId, qint64 sessionId) void Server::sendIsl_Response(const Response &item, int serverId, qint64 sessionId)
{ {
IslMessage msg; IslMessage msg;
msg.set_message_type(IslMessage::RESPONSE); msg.set_message_type(IslMessage::RESPONSE);
if (sessionId != -1) if (sessionId != -1)
msg.set_session_id(sessionId); msg.set_session_id(sessionId);
msg.mutable_response()->CopyFrom(item); msg.mutable_response()->CopyFrom(item);
emit sigSendIslMessage(msg, serverId); emit sigSendIslMessage(msg, serverId);
} }
void Server::sendIsl_SessionEvent(const SessionEvent &item, int serverId, qint64 sessionId) void Server::sendIsl_SessionEvent(const SessionEvent &item, int serverId, qint64 sessionId)
{ {
IslMessage msg; IslMessage msg;
msg.set_message_type(IslMessage::SESSION_EVENT); msg.set_message_type(IslMessage::SESSION_EVENT);
if (sessionId != -1) if (sessionId != -1)
msg.set_session_id(sessionId); msg.set_session_id(sessionId);
msg.mutable_session_event()->CopyFrom(item); msg.mutable_session_event()->CopyFrom(item);
emit sigSendIslMessage(msg, serverId); emit sigSendIslMessage(msg, serverId);
} }
void Server::sendIsl_GameEventContainer(const GameEventContainer &item, int serverId, qint64 sessionId) void Server::sendIsl_GameEventContainer(const GameEventContainer &item, int serverId, qint64 sessionId)
{ {
IslMessage msg; IslMessage msg;
msg.set_message_type(IslMessage::GAME_EVENT_CONTAINER); msg.set_message_type(IslMessage::GAME_EVENT_CONTAINER);
if (sessionId != -1) if (sessionId != -1)
msg.set_session_id(sessionId); msg.set_session_id(sessionId);
msg.mutable_game_event_container()->CopyFrom(item); msg.mutable_game_event_container()->CopyFrom(item);
emit sigSendIslMessage(msg, serverId); emit sigSendIslMessage(msg, serverId);
} }
void Server::sendIsl_RoomEvent(const RoomEvent &item, int serverId, qint64 sessionId) void Server::sendIsl_RoomEvent(const RoomEvent &item, int serverId, qint64 sessionId)
{ {
IslMessage msg; IslMessage msg;
msg.set_message_type(IslMessage::ROOM_EVENT); msg.set_message_type(IslMessage::ROOM_EVENT);
if (sessionId != -1) if (sessionId != -1)
msg.set_session_id(sessionId); msg.set_session_id(sessionId);
msg.mutable_room_event()->CopyFrom(item); msg.mutable_room_event()->CopyFrom(item);
emit sigSendIslMessage(msg, serverId); emit sigSendIslMessage(msg, serverId);
} }
void Server::sendIsl_GameCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId, int playerId) void Server::sendIsl_GameCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId, int playerId)
{ {
IslMessage msg; IslMessage msg;
msg.set_message_type(IslMessage::GAME_COMMAND_CONTAINER); msg.set_message_type(IslMessage::GAME_COMMAND_CONTAINER);
msg.set_session_id(sessionId); msg.set_session_id(sessionId);
msg.set_player_id(playerId); msg.set_player_id(playerId);
CommandContainer *cont = msg.mutable_game_command(); CommandContainer *cont = msg.mutable_game_command();
cont->CopyFrom(item); cont->CopyFrom(item);
cont->set_room_id(roomId); cont->set_room_id(roomId);
emit sigSendIslMessage(msg, serverId); emit sigSendIslMessage(msg, serverId);
} }
void Server::sendIsl_RoomCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId) void Server::sendIsl_RoomCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId)
{ {
IslMessage msg; IslMessage msg;
msg.set_message_type(IslMessage::ROOM_COMMAND_CONTAINER); msg.set_message_type(IslMessage::ROOM_COMMAND_CONTAINER);
msg.set_session_id(sessionId); msg.set_session_id(sessionId);
CommandContainer *cont = msg.mutable_room_command(); CommandContainer *cont = msg.mutable_room_command();
cont->CopyFrom(item); cont->CopyFrom(item);
cont->set_room_id(roomId); cont->set_room_id(roomId);
emit sigSendIslMessage(msg, serverId); emit sigSendIslMessage(msg, serverId);
} }

View file

@ -31,87 +31,87 @@ enum AuthenticationResult { NotLoggedIn = 0, PasswordRight = 1, UnknownUser = 2,
class Server : public QObject class Server : public QObject
{ {
Q_OBJECT Q_OBJECT
signals: signals:
void pingClockTimeout(); void pingClockTimeout();
void sigSendIslMessage(const IslMessage &message, int serverId); void sigSendIslMessage(const IslMessage &message, int serverId);
void endSession(qint64 sessionId); void endSession(qint64 sessionId);
private slots: private slots:
void broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl = false); void broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl = false);
public: public:
mutable QReadWriteLock clientsLock, roomsLock; // locking order: roomsLock before clientsLock mutable QReadWriteLock clientsLock, roomsLock; // locking order: roomsLock before clientsLock
Server(bool _threaded, QObject *parent = 0); Server(bool _threaded, QObject *parent = 0);
~Server(); ~Server();
void setThreaded(bool _threaded) { threaded = _threaded; } void setThreaded(bool _threaded) { threaded = _threaded; }
AuthenticationResult loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reason, int &secondsLeft); AuthenticationResult loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reason, int &secondsLeft);
const QMap<int, Server_Room *> &getRooms() { return rooms; } const QMap<int, Server_Room *> &getRooms() { return rooms; }
Server_AbstractUserInterface *findUser(const QString &userName) const; Server_AbstractUserInterface *findUser(const QString &userName) const;
const QMap<QString, Server_ProtocolHandler *> &getUsers() const { return users; } const QMap<QString, Server_ProtocolHandler *> &getUsers() const { return users; }
const QMap<qint64, Server_ProtocolHandler *> &getUsersBySessionId() const { return usersBySessionId; } const QMap<qint64, Server_ProtocolHandler *> &getUsersBySessionId() const { return usersBySessionId; }
void addClient(Server_ProtocolHandler *player); void addClient(Server_ProtocolHandler *player);
void removeClient(Server_ProtocolHandler *player); void removeClient(Server_ProtocolHandler *player);
virtual QString getLoginMessage() const { return QString(); } virtual QString getLoginMessage() const { return QString(); }
virtual bool getGameShouldPing() const { return false; } virtual bool getGameShouldPing() const { return false; }
virtual int getMaxGameInactivityTime() const { return 9999999; } virtual int getMaxGameInactivityTime() const { return 9999999; }
virtual int getMaxPlayerInactivityTime() const { return 9999999; } virtual int getMaxPlayerInactivityTime() const { return 9999999; }
virtual int getMessageCountingInterval() const { return 0; } virtual int getMessageCountingInterval() const { return 0; }
virtual int getMaxMessageCountPerInterval() const { return 0; } virtual int getMaxMessageCountPerInterval() const { return 0; }
virtual int getMaxMessageSizePerInterval() const { return 0; } virtual int getMaxMessageSizePerInterval() const { return 0; }
virtual int getMaxGamesPerUser() const { return 0; } virtual int getMaxGamesPerUser() const { return 0; }
virtual bool getThreaded() const { return false; } virtual bool getThreaded() const { return false; }
Server_DatabaseInterface *getDatabaseInterface() const; Server_DatabaseInterface *getDatabaseInterface() const;
int getNextLocalGameId() { QMutexLocker locker(&nextLocalGameIdMutex); return ++nextLocalGameId; } int getNextLocalGameId() { QMutexLocker locker(&nextLocalGameIdMutex); return ++nextLocalGameId; }
void sendIsl_Response(const Response &item, int serverId = -1, qint64 sessionId = -1); void sendIsl_Response(const Response &item, int serverId = -1, qint64 sessionId = -1);
void sendIsl_SessionEvent(const SessionEvent &item, int serverId = -1, qint64 sessionId = -1); void sendIsl_SessionEvent(const SessionEvent &item, int serverId = -1, qint64 sessionId = -1);
void sendIsl_GameEventContainer(const GameEventContainer &item, int serverId = -1, qint64 sessionId = -1); void sendIsl_GameEventContainer(const GameEventContainer &item, int serverId = -1, qint64 sessionId = -1);
void sendIsl_RoomEvent(const RoomEvent &item, int serverId = -1, qint64 sessionId = -1); void sendIsl_RoomEvent(const RoomEvent &item, int serverId = -1, qint64 sessionId = -1);
void sendIsl_GameCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId, int playerId); void sendIsl_GameCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId, int playerId);
void sendIsl_RoomCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId); void sendIsl_RoomCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId);
void addExternalUser(const ServerInfo_User &userInfo); void addExternalUser(const ServerInfo_User &userInfo);
void removeExternalUser(const QString &userName); void removeExternalUser(const QString &userName);
const QMap<QString, Server_AbstractUserInterface *> &getExternalUsers() const { return externalUsers; } const QMap<QString, Server_AbstractUserInterface *> &getExternalUsers() const { return externalUsers; }
void addPersistentPlayer(const QString &userName, int roomId, int gameId, int playerId); void addPersistentPlayer(const QString &userName, int roomId, int gameId, int playerId);
void removePersistentPlayer(const QString &userName, int roomId, int gameId, int playerId); void removePersistentPlayer(const QString &userName, int roomId, int gameId, int playerId);
QList<PlayerReference> getPersistentPlayerReferences(const QString &userName) const; QList<PlayerReference> getPersistentPlayerReferences(const QString &userName) const;
private: private:
bool threaded; bool threaded;
QMultiMap<QString, PlayerReference> persistentPlayers; QMultiMap<QString, PlayerReference> persistentPlayers;
mutable QReadWriteLock persistentPlayersLock; mutable QReadWriteLock persistentPlayersLock;
int nextLocalGameId; int nextLocalGameId;
QMutex nextLocalGameIdMutex; QMutex nextLocalGameIdMutex;
protected slots: protected slots:
void externalUserJoined(const ServerInfo_User &userInfo); void externalUserJoined(const ServerInfo_User &userInfo);
void externalUserLeft(const QString &userName); void externalUserLeft(const QString &userName);
void externalRoomUserJoined(int roomId, const ServerInfo_User &userInfo); void externalRoomUserJoined(int roomId, const ServerInfo_User &userInfo);
void externalRoomUserLeft(int roomId, const QString &userName); void externalRoomUserLeft(int roomId, const QString &userName);
void externalRoomSay(int roomId, const QString &userName, const QString &message); void externalRoomSay(int roomId, const QString &userName, const QString &message);
void externalRoomGameListChanged(int roomId, const ServerInfo_Game &gameInfo); void externalRoomGameListChanged(int roomId, const ServerInfo_Game &gameInfo);
void externalJoinGameCommandReceived(const Command_JoinGame &cmd, int cmdId, int roomId, int serverId, qint64 sessionId); void externalJoinGameCommandReceived(const Command_JoinGame &cmd, int cmdId, int roomId, int serverId, qint64 sessionId);
void externalGameCommandContainerReceived(const CommandContainer &cont, int playerId, int serverId, qint64 sessionId); void externalGameCommandContainerReceived(const CommandContainer &cont, int playerId, int serverId, qint64 sessionId);
void externalGameEventContainerReceived(const GameEventContainer &cont, qint64 sessionId); void externalGameEventContainerReceived(const GameEventContainer &cont, qint64 sessionId);
void externalResponseReceived(const Response &resp, qint64 sessionId); void externalResponseReceived(const Response &resp, qint64 sessionId);
virtual void doSendIslMessage(const IslMessage &msg, int serverId) { } virtual void doSendIslMessage(const IslMessage & /* msg */, int /* serverId */) { }
protected: protected:
void prepareDestroy(); void prepareDestroy();
void setDatabaseInterface(Server_DatabaseInterface *_databaseInterface); void setDatabaseInterface(Server_DatabaseInterface *_databaseInterface);
QList<Server_ProtocolHandler *> clients; QList<Server_ProtocolHandler *> clients;
QMap<qint64, Server_ProtocolHandler *> usersBySessionId; QMap<qint64, Server_ProtocolHandler *> usersBySessionId;
QMap<QString, Server_ProtocolHandler *> users; QMap<QString, Server_ProtocolHandler *> users;
QMap<qint64, Server_AbstractUserInterface *> externalUsersBySessionId; QMap<qint64, Server_AbstractUserInterface *> externalUsersBySessionId;
QMap<QString, Server_AbstractUserInterface *> externalUsers; QMap<QString, Server_AbstractUserInterface *> externalUsers;
QMap<int, Server_Room *> rooms; QMap<int, Server_Room *> rooms;
QMap<QThread *, Server_DatabaseInterface *> databaseInterfaces; QMap<QThread *, Server_DatabaseInterface *> databaseInterfaces;
int getUsersCount() const; int getUsersCount() const;
int getGamesCount() const; int getGamesCount() const;
void addRoom(Server_Room *newRoom); void addRoom(Server_Room *newRoom);
}; };
#endif #endif

View file

@ -15,82 +15,82 @@
void Server_AbstractUserInterface::sendProtocolItemByType(ServerMessage::MessageType type, const ::google::protobuf::Message &item) void Server_AbstractUserInterface::sendProtocolItemByType(ServerMessage::MessageType type, const ::google::protobuf::Message &item)
{ {
switch (type) { switch (type) {
case ServerMessage::RESPONSE: sendProtocolItem(static_cast<const Response &>(item)); break; case ServerMessage::RESPONSE: sendProtocolItem(static_cast<const Response &>(item)); break;
case ServerMessage::SESSION_EVENT: sendProtocolItem(static_cast<const SessionEvent &>(item)); break; case ServerMessage::SESSION_EVENT: sendProtocolItem(static_cast<const SessionEvent &>(item)); break;
case ServerMessage::GAME_EVENT_CONTAINER: sendProtocolItem(static_cast<const GameEventContainer &>(item)); break; case ServerMessage::GAME_EVENT_CONTAINER: sendProtocolItem(static_cast<const GameEventContainer &>(item)); break;
case ServerMessage::ROOM_EVENT: sendProtocolItem(static_cast<const RoomEvent &>(item)); break; case ServerMessage::ROOM_EVENT: sendProtocolItem(static_cast<const RoomEvent &>(item)); break;
} }
} }
SessionEvent *Server_AbstractUserInterface::prepareSessionEvent(const ::google::protobuf::Message &sessionEvent) SessionEvent *Server_AbstractUserInterface::prepareSessionEvent(const ::google::protobuf::Message &sessionEvent)
{ {
SessionEvent *event = new SessionEvent; SessionEvent *event = new SessionEvent;
event->GetReflection()->MutableMessage(event, sessionEvent.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(sessionEvent); event->GetReflection()->MutableMessage(event, sessionEvent.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(sessionEvent);
return event; return event;
} }
void Server_AbstractUserInterface::sendResponseContainer(const ResponseContainer &responseContainer, Response::ResponseCode responseCode) void Server_AbstractUserInterface::sendResponseContainer(const ResponseContainer &responseContainer, Response::ResponseCode responseCode)
{ {
const QList<QPair<ServerMessage::MessageType, ::google::protobuf::Message *> > &preResponseQueue = responseContainer.getPreResponseQueue(); const QList<QPair<ServerMessage::MessageType, ::google::protobuf::Message *> > &preResponseQueue = responseContainer.getPreResponseQueue();
for (int i = 0; i < preResponseQueue.size(); ++i) for (int i = 0; i < preResponseQueue.size(); ++i)
sendProtocolItemByType(preResponseQueue[i].first, *preResponseQueue[i].second); sendProtocolItemByType(preResponseQueue[i].first, *preResponseQueue[i].second);
if (responseCode != Response::RespNothing) { if (responseCode != Response::RespNothing) {
Response response; Response response;
response.set_cmd_id(responseContainer.getCmdId()); response.set_cmd_id(responseContainer.getCmdId());
response.set_response_code(responseCode); response.set_response_code(responseCode);
::google::protobuf::Message *responseExtension = responseContainer.getResponseExtension(); ::google::protobuf::Message *responseExtension = responseContainer.getResponseExtension();
if (responseExtension) if (responseExtension)
response.GetReflection()->MutableMessage(&response, responseExtension->GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(*responseExtension); response.GetReflection()->MutableMessage(&response, responseExtension->GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(*responseExtension);
sendProtocolItem(response); sendProtocolItem(response);
} }
const QList<QPair<ServerMessage::MessageType, ::google::protobuf::Message *> > &postResponseQueue = responseContainer.getPostResponseQueue(); const QList<QPair<ServerMessage::MessageType, ::google::protobuf::Message *> > &postResponseQueue = responseContainer.getPostResponseQueue();
for (int i = 0; i < postResponseQueue.size(); ++i) for (int i = 0; i < postResponseQueue.size(); ++i)
sendProtocolItemByType(postResponseQueue[i].first, *postResponseQueue[i].second); sendProtocolItemByType(postResponseQueue[i].first, *postResponseQueue[i].second);
} }
void Server_AbstractUserInterface::playerRemovedFromGame(Server_Game *game) void Server_AbstractUserInterface::playerRemovedFromGame(Server_Game *game)
{ {
qDebug() << "Server_AbstractUserInterface::playerRemovedFromGame(): gameId =" << game->getGameId(); qDebug() << "Server_AbstractUserInterface::playerRemovedFromGame(): gameId =" << game->getGameId();
QMutexLocker locker(&gameListMutex); QMutexLocker locker(&gameListMutex);
games.remove(game->getGameId()); games.remove(game->getGameId());
} }
void Server_AbstractUserInterface::playerAddedToGame(int gameId, int roomId, int playerId) void Server_AbstractUserInterface::playerAddedToGame(int gameId, int roomId, int playerId)
{ {
qDebug() << "Server_AbstractUserInterface::playerAddedToGame(): gameId =" << gameId; qDebug() << "Server_AbstractUserInterface::playerAddedToGame(): gameId =" << gameId;
QMutexLocker locker(&gameListMutex); QMutexLocker locker(&gameListMutex);
games.insert(gameId, QPair<int, int>(roomId, playerId)); games.insert(gameId, QPair<int, int>(roomId, playerId));
} }
void Server_AbstractUserInterface::joinPersistentGames(ResponseContainer &rc) void Server_AbstractUserInterface::joinPersistentGames(ResponseContainer &rc)
{ {
QList<PlayerReference> gamesToJoin = server->getPersistentPlayerReferences(QString::fromStdString(userInfo->name())); QList<PlayerReference> gamesToJoin = server->getPersistentPlayerReferences(QString::fromStdString(userInfo->name()));
server->roomsLock.lockForRead(); server->roomsLock.lockForRead();
for (int i = 0; i < gamesToJoin.size(); ++i) { for (int i = 0; i < gamesToJoin.size(); ++i) {
const PlayerReference &pr = gamesToJoin.at(i); const PlayerReference &pr = gamesToJoin.at(i);
Server_Room *room = server->getRooms().value(pr.getRoomId()); Server_Room *room = server->getRooms().value(pr.getRoomId());
if (!room) if (!room)
continue; continue;
QReadLocker roomGamesLocker(&room->gamesLock); QReadLocker roomGamesLocker(&room->gamesLock);
Server_Game *game = room->getGames().value(pr.getGameId()); Server_Game *game = room->getGames().value(pr.getGameId());
if (!game) if (!game)
continue; continue;
QMutexLocker gameLocker(&game->gameMutex); QMutexLocker gameLocker(&game->gameMutex);
Server_Player *player = game->getPlayers().value(pr.getPlayerId()); Server_Player *player = game->getPlayers().value(pr.getPlayerId());
player->setUserInterface(this); player->setUserInterface(this);
playerAddedToGame(game->getGameId(), room->getId(), player->getPlayerId()); playerAddedToGame(game->getGameId(), room->getId(), player->getPlayerId());
game->createGameJoinedEvent(player, rc, true); game->createGameJoinedEvent(player, rc, true);
} }
server->roomsLock.unlock(); server->roomsLock.unlock();
} }

View file

@ -18,31 +18,31 @@ class Server_Game;
class Server_AbstractUserInterface : public ServerInfo_User_Container { class Server_AbstractUserInterface : public ServerInfo_User_Container {
private: private:
mutable QMutex gameListMutex; mutable QMutex gameListMutex;
QMap<int, QPair<int, int> > games; // gameId -> (roomId, playerId) QMap<int, QPair<int, int> > games; // gameId -> (roomId, playerId)
protected: protected:
Server *server; Server *server;
public: public:
Server_AbstractUserInterface(Server *_server) : server(_server) { } Server_AbstractUserInterface(Server *_server) : server(_server) { }
Server_AbstractUserInterface(Server *_server, const ServerInfo_User_Container &other) : ServerInfo_User_Container(other), server(_server) { } Server_AbstractUserInterface(Server *_server, const ServerInfo_User_Container &other) : ServerInfo_User_Container(other), server(_server) { }
virtual ~Server_AbstractUserInterface() { } virtual ~Server_AbstractUserInterface() { }
virtual int getLastCommandTime() const = 0; virtual int getLastCommandTime() const = 0;
void playerRemovedFromGame(Server_Game *game); void playerRemovedFromGame(Server_Game *game);
void playerAddedToGame(int gameId, int roomId, int playerId); void playerAddedToGame(int gameId, int roomId, int playerId);
void joinPersistentGames(ResponseContainer &rc); void joinPersistentGames(ResponseContainer &rc);
QMap<int, QPair<int, int> > getGames() const { QMutexLocker locker(&gameListMutex); return games; } QMap<int, QPair<int, int> > getGames() const { QMutexLocker locker(&gameListMutex); return games; }
virtual void sendProtocolItem(const Response &item) = 0; virtual void sendProtocolItem(const Response &item) = 0;
virtual void sendProtocolItem(const SessionEvent &item) = 0; virtual void sendProtocolItem(const SessionEvent &item) = 0;
virtual void sendProtocolItem(const GameEventContainer &item) = 0; virtual void sendProtocolItem(const GameEventContainer &item) = 0;
virtual void sendProtocolItem(const RoomEvent &item) = 0; virtual void sendProtocolItem(const RoomEvent &item) = 0;
void sendProtocolItemByType(ServerMessage::MessageType type, const ::google::protobuf::Message &item); void sendProtocolItemByType(ServerMessage::MessageType type, const ::google::protobuf::Message &item);
static SessionEvent *prepareSessionEvent(const ::google::protobuf::Message &sessionEvent); static SessionEvent *prepareSessionEvent(const ::google::protobuf::Message &sessionEvent);
void sendResponseContainer(const ResponseContainer &responseContainer, Response::ResponseCode responseCode); void sendResponseContainer(const ResponseContainer &responseContainer, Response::ResponseCode responseCode);
}; };
#endif #endif

View file

@ -14,17 +14,17 @@ Server_Arrow::Server_Arrow(int _id, Server_Card *_startCard, Server_ArrowTarget
void Server_Arrow::getInfo(ServerInfo_Arrow *info) void Server_Arrow::getInfo(ServerInfo_Arrow *info)
{ {
info->set_id(id); info->set_id(id);
info->set_start_player_id(startCard->getZone()->getPlayer()->getPlayerId()); info->set_start_player_id(startCard->getZone()->getPlayer()->getPlayerId());
info->set_start_zone(startCard->getZone()->getName().toStdString()); info->set_start_zone(startCard->getZone()->getName().toStdString());
info->set_start_card_id(startCard->getId()); info->set_start_card_id(startCard->getId());
info->mutable_arrow_color()->CopyFrom(arrowColor); info->mutable_arrow_color()->CopyFrom(arrowColor);
Server_Card *targetCard = qobject_cast<Server_Card *>(targetItem); Server_Card *targetCard = qobject_cast<Server_Card *>(targetItem);
if (targetCard) { if (targetCard) {
info->set_target_player_id(targetCard->getZone()->getPlayer()->getPlayerId()); info->set_target_player_id(targetCard->getZone()->getPlayer()->getPlayerId());
info->set_target_zone(targetCard->getZone()->getName().toStdString()); info->set_target_zone(targetCard->getZone()->getName().toStdString());
info->set_target_card_id(targetCard->getId()); info->set_target_card_id(targetCard->getId());
} else } else
info->set_target_player_id(static_cast<Server_Player *>(targetItem)->getPlayerId()); info->set_target_player_id(static_cast<Server_Player *>(targetItem)->getPlayerId());
} }

View file

@ -9,18 +9,18 @@ class ServerInfo_Arrow;
class Server_Arrow { class Server_Arrow {
private: private:
int id; int id;
Server_Card *startCard; Server_Card *startCard;
Server_ArrowTarget *targetItem; Server_ArrowTarget *targetItem;
color arrowColor; color arrowColor;
public: public:
Server_Arrow(int _id, Server_Card *_startCard, Server_ArrowTarget *_targetItem, const color &_arrowColor); Server_Arrow(int _id, Server_Card *_startCard, Server_ArrowTarget *_targetItem, const color &_arrowColor);
int getId() const { return id; } int getId() const { return id; }
Server_Card *getStartCard() const { return startCard; } Server_Card *getStartCard() const { return startCard; }
Server_ArrowTarget *getTargetItem() const { return targetItem; } Server_ArrowTarget *getTargetItem() const { return targetItem; }
const color &getColor() const { return arrowColor; } const color &getColor() const { return arrowColor; }
void getInfo(ServerInfo_Arrow *info); void getInfo(ServerInfo_Arrow *info);
}; };
#endif #endif

View file

@ -4,7 +4,7 @@
#include <QObject> #include <QObject>
class Server_ArrowTarget : public QObject { class Server_ArrowTarget : public QObject {
Q_OBJECT Q_OBJECT
}; };
#endif #endif

View file

@ -23,138 +23,138 @@
#include "pb/serverinfo_card.pb.h" #include "pb/serverinfo_card.pb.h"
Server_Card::Server_Card(QString _name, int _id, int _coord_x, int _coord_y, Server_CardZone *_zone) Server_Card::Server_Card(QString _name, int _id, int _coord_x, int _coord_y, Server_CardZone *_zone)
: zone(_zone), id(_id), coord_x(_coord_x), coord_y(_coord_y), name(_name), tapped(false), attacking(false), facedown(false), color(QString()), power(-1), toughness(-1), annotation(QString()), destroyOnZoneChange(false), doesntUntap(false), parentCard(0) : zone(_zone), id(_id), coord_x(_coord_x), coord_y(_coord_y), name(_name), tapped(false), attacking(false), facedown(false), color(QString()), power(-1), toughness(-1), annotation(QString()), destroyOnZoneChange(false), doesntUntap(false), parentCard(0)
{ {
} }
Server_Card::~Server_Card() Server_Card::~Server_Card()
{ {
// setParentCard(0) leads to the item being removed from our list, so we can't iterate properly // setParentCard(0) leads to the item being removed from our list, so we can't iterate properly
while (!attachedCards.isEmpty()) while (!attachedCards.isEmpty())
attachedCards.first()->setParentCard(0); attachedCards.first()->setParentCard(0);
if (parentCard) if (parentCard)
parentCard->removeAttachedCard(this); parentCard->removeAttachedCard(this);
} }
void Server_Card::resetState() void Server_Card::resetState()
{ {
counters.clear(); counters.clear();
setTapped(false); setTapped(false);
setAttacking(false); setAttacking(false);
power = -1; power = -1;
toughness = -1; toughness = -1;
setAnnotation(QString()); setAnnotation(QString());
setDoesntUntap(false); setDoesntUntap(false);
} }
QString Server_Card::setAttribute(CardAttribute attribute, const QString &avalue, bool allCards) QString Server_Card::setAttribute(CardAttribute attribute, const QString &avalue, bool allCards)
{ {
switch (attribute) { switch (attribute) {
case AttrTapped: { case AttrTapped: {
bool value = avalue == "1"; bool value = avalue == "1";
if (!(!value && allCards && doesntUntap)) if (!(!value && allCards && doesntUntap))
setTapped(value); setTapped(value);
break; break;
} }
case AttrAttacking: setAttacking(avalue == "1"); break; case AttrAttacking: setAttacking(avalue == "1"); break;
case AttrFaceDown: setFaceDown(avalue == "1"); break; case AttrFaceDown: setFaceDown(avalue == "1"); break;
case AttrColor: setColor(avalue); break; case AttrColor: setColor(avalue); break;
case AttrPT: setPT(avalue); return getPT(); case AttrPT: setPT(avalue); return getPT();
case AttrAnnotation: setAnnotation(avalue); break; case AttrAnnotation: setAnnotation(avalue); break;
case AttrDoesntUntap: setDoesntUntap(avalue == "1"); break; case AttrDoesntUntap: setDoesntUntap(avalue == "1"); break;
} }
return avalue; return avalue;
} }
void Server_Card::setCounter(int id, int value) void Server_Card::setCounter(int id, int value)
{ {
if (value) if (value)
counters.insert(id, value); counters.insert(id, value);
else else
counters.remove(id); counters.remove(id);
} }
void Server_Card::setPT(const QString &_pt) void Server_Card::setPT(const QString &_pt)
{ {
if (_pt.isEmpty()) { if (_pt.isEmpty()) {
power = 0; power = 0;
toughness = -1; toughness = -1;
} else { } else {
int sep = _pt.indexOf('/'); int sep = _pt.indexOf('/');
QString p1 = _pt.left(sep); QString p1 = _pt.left(sep);
QString p2 = _pt.mid(sep + 1); QString p2 = _pt.mid(sep + 1);
if (p1.isEmpty() || p2.isEmpty()) if (p1.isEmpty() || p2.isEmpty())
return; return;
if ((p1[0] == '+') || (p2[0] == '+')) { if ((p1[0] == '+') || (p2[0] == '+')) {
if (power < 0) if (power < 0)
power = 0; power = 0;
if (toughness < 0) if (toughness < 0)
toughness = 0; toughness = 0;
} }
if (p1[0] == '+') if (p1[0] == '+')
power += p1.mid(1).toInt(); power += p1.mid(1).toInt();
else else
power = p1.toInt(); power = p1.toInt();
if (p2[0] == '+') if (p2[0] == '+')
toughness += p2.mid(1).toInt(); toughness += p2.mid(1).toInt();
else else
toughness = p2.toInt(); toughness = p2.toInt();
} }
} }
QString Server_Card::getPT() const QString Server_Card::getPT() const
{ {
if (toughness < 0) if (toughness < 0)
return QString(""); return QString("");
return QString::number(power) + "/" + QString::number(toughness); return QString::number(power) + "/" + QString::number(toughness);
} }
void Server_Card::setParentCard(Server_Card *_parentCard) void Server_Card::setParentCard(Server_Card *_parentCard)
{ {
if (parentCard) if (parentCard)
parentCard->removeAttachedCard(this); parentCard->removeAttachedCard(this);
parentCard = _parentCard; parentCard = _parentCard;
if (parentCard) if (parentCard)
parentCard->addAttachedCard(this); parentCard->addAttachedCard(this);
} }
void Server_Card::getInfo(ServerInfo_Card *info) void Server_Card::getInfo(ServerInfo_Card *info)
{ {
QString displayedName = facedown ? QString() : name; QString displayedName = facedown ? QString() : name;
info->set_id(id); info->set_id(id);
info->set_name(displayedName.toStdString()); info->set_name(displayedName.toStdString());
info->set_x(coord_x); info->set_x(coord_x);
info->set_y(coord_y); info->set_y(coord_y);
if (facedown) if (facedown)
info->set_face_down(true); info->set_face_down(true);
info->set_tapped(tapped); info->set_tapped(tapped);
if (attacking) if (attacking)
info->set_attacking(true); info->set_attacking(true);
if (!color.isEmpty()) if (!color.isEmpty())
info->set_color(color.toStdString()); info->set_color(color.toStdString());
const QString ptStr = getPT(); const QString ptStr = getPT();
if (!ptStr.isEmpty()) if (!ptStr.isEmpty())
info->set_pt(ptStr.toStdString()); info->set_pt(ptStr.toStdString());
if (!annotation.isEmpty()) if (!annotation.isEmpty())
info->set_annotation(annotation.toStdString()); info->set_annotation(annotation.toStdString());
if (destroyOnZoneChange) if (destroyOnZoneChange)
info->set_destroy_on_zone_change(true); info->set_destroy_on_zone_change(true);
if (doesntUntap) if (doesntUntap)
info->set_doesnt_untap(true); info->set_doesnt_untap(true);
QMapIterator<int, int> cardCounterIterator(counters); QMapIterator<int, int> cardCounterIterator(counters);
while (cardCounterIterator.hasNext()) { while (cardCounterIterator.hasNext()) {
cardCounterIterator.next(); cardCounterIterator.next();
ServerInfo_CardCounter *counterInfo = info->add_counter_list(); ServerInfo_CardCounter *counterInfo = info->add_counter_list();
counterInfo->set_id(cardCounterIterator.key()); counterInfo->set_id(cardCounterIterator.key());
counterInfo->set_value(cardCounterIterator.value()); counterInfo->set_value(cardCounterIterator.value());
} }
if (parentCard) { if (parentCard) {
info->set_attach_player_id(parentCard->getZone()->getPlayer()->getPlayerId()); info->set_attach_player_id(parentCard->getZone()->getPlayer()->getPlayerId());
info->set_attach_zone(parentCard->getZone()->getName().toStdString()); info->set_attach_zone(parentCard->getZone()->getName().toStdString());
info->set_attach_card_id(parentCard->getId()); info->set_attach_card_id(parentCard->getId());
} }
} }

View file

@ -29,68 +29,68 @@ class Server_CardZone;
class ServerInfo_Card; class ServerInfo_Card;
class Server_Card : public Server_ArrowTarget { class Server_Card : public Server_ArrowTarget {
Q_OBJECT Q_OBJECT
private: private:
Server_CardZone *zone; Server_CardZone *zone;
int id; int id;
int coord_x, coord_y; int coord_x, coord_y;
QString name; QString name;
QMap<int, int> counters; QMap<int, int> counters;
bool tapped; bool tapped;
bool attacking; bool attacking;
bool facedown; bool facedown;
QString color; QString color;
int power, toughness; int power, toughness;
QString annotation; QString annotation;
bool destroyOnZoneChange; bool destroyOnZoneChange;
bool doesntUntap; bool doesntUntap;
Server_Card *parentCard; Server_Card *parentCard;
QList<Server_Card *> attachedCards; QList<Server_Card *> attachedCards;
public: public:
Server_Card(QString _name, int _id, int _coord_x, int _coord_y, Server_CardZone *_zone = 0); Server_Card(QString _name, int _id, int _coord_x, int _coord_y, Server_CardZone *_zone = 0);
~Server_Card(); ~Server_Card();
Server_CardZone *getZone() const { return zone; } Server_CardZone *getZone() const { return zone; }
void setZone(Server_CardZone *_zone) { zone = _zone; } void setZone(Server_CardZone *_zone) { zone = _zone; }
int getId() const { return id; } int getId() const { return id; }
int getX() const { return coord_x; } int getX() const { return coord_x; }
int getY() const { return coord_y; } int getY() const { return coord_y; }
QString getName() const { return name; } QString getName() const { return name; }
const QMap<int, int> &getCounters() const { return counters; } const QMap<int, int> &getCounters() const { return counters; }
int getCounter(int id) const { return counters.value(id, 0); } int getCounter(int id) const { return counters.value(id, 0); }
bool getTapped() const { return tapped; } bool getTapped() const { return tapped; }
bool getAttacking() const { return attacking; } bool getAttacking() const { return attacking; }
bool getFaceDown() const { return facedown; } bool getFaceDown() const { return facedown; }
QString getColor() const { return color; } QString getColor() const { return color; }
QString getPT() const; QString getPT() const;
QString getAnnotation() const { return annotation; } QString getAnnotation() const { return annotation; }
bool getDoesntUntap() const { return doesntUntap; } bool getDoesntUntap() const { return doesntUntap; }
bool getDestroyOnZoneChange() const { return destroyOnZoneChange; } bool getDestroyOnZoneChange() const { return destroyOnZoneChange; }
Server_Card *getParentCard() const { return parentCard; } Server_Card *getParentCard() const { return parentCard; }
const QList<Server_Card *> &getAttachedCards() const { return attachedCards; } const QList<Server_Card *> &getAttachedCards() const { return attachedCards; }
void setId(int _id) { id = _id; } void setId(int _id) { id = _id; }
void setCoords(int x, int y) { coord_x = x; coord_y = y; } void setCoords(int x, int y) { coord_x = x; coord_y = y; }
void setName(const QString &_name) { name = _name; } void setName(const QString &_name) { name = _name; }
void setCounter(int id, int value); void setCounter(int id, int value);
void setTapped(bool _tapped) { tapped = _tapped; } void setTapped(bool _tapped) { tapped = _tapped; }
void setAttacking(bool _attacking) { attacking = _attacking; } void setAttacking(bool _attacking) { attacking = _attacking; }
void setFaceDown(bool _facedown) { facedown = _facedown; } void setFaceDown(bool _facedown) { facedown = _facedown; }
void setColor(const QString &_color) { color = _color; } void setColor(const QString &_color) { color = _color; }
void setPT(const QString &_pt); void setPT(const QString &_pt);
void setAnnotation(const QString &_annotation) { annotation = _annotation; } void setAnnotation(const QString &_annotation) { annotation = _annotation; }
void setDestroyOnZoneChange(bool _destroy) { destroyOnZoneChange = _destroy; } void setDestroyOnZoneChange(bool _destroy) { destroyOnZoneChange = _destroy; }
void setDoesntUntap(bool _doesntUntap) { doesntUntap = _doesntUntap; } void setDoesntUntap(bool _doesntUntap) { doesntUntap = _doesntUntap; }
void setParentCard(Server_Card *_parentCard); void setParentCard(Server_Card *_parentCard);
void addAttachedCard(Server_Card *card) { attachedCards.append(card); } void addAttachedCard(Server_Card *card) { attachedCards.append(card); }
void removeAttachedCard(Server_Card *card) { attachedCards.removeAt(attachedCards.indexOf(card)); } void removeAttachedCard(Server_Card *card) { attachedCards.removeAt(attachedCards.indexOf(card)); }
void resetState(); void resetState();
QString setAttribute(CardAttribute attribute, const QString &avalue, bool allCards); QString setAttribute(CardAttribute attribute, const QString &avalue, bool allCards);
void getInfo(ServerInfo_Card *info); void getInfo(ServerInfo_Card *info);
}; };
#endif #endif

View file

@ -33,48 +33,48 @@ class GameEventStorage;
class Server_CardZone { class Server_CardZone {
private: private:
Server_Player *player; Server_Player *player;
QString name; QString name;
bool has_coords; bool has_coords;
ServerInfo_Zone::ZoneType type; ServerInfo_Zone::ZoneType type;
int cardsBeingLookedAt; int cardsBeingLookedAt;
QSet<int> playersWithWritePermission; QSet<int> playersWithWritePermission;
bool alwaysRevealTopCard; bool alwaysRevealTopCard;
QList<Server_Card *> cards; QList<Server_Card *> cards;
QMap<int, QMap<int, Server_Card *> > coordinateMap; // y -> (x -> card) QMap<int, QMap<int, Server_Card *> > coordinateMap; // y -> (x -> card)
QMap<int, QMultiMap<QString, int> > freePilesMap; // y -> (cardName -> x) QMap<int, QMultiMap<QString, int> > freePilesMap; // y -> (cardName -> x)
QMap<int, int> freeSpaceMap; // y -> x QMap<int, int> freeSpaceMap; // y -> x
void removeCardFromCoordMap(Server_Card *card, int oldX, int oldY); void removeCardFromCoordMap(Server_Card *card, int oldX, int oldY);
void insertCardIntoCoordMap(Server_Card *card, int x, int y); void insertCardIntoCoordMap(Server_Card *card, int x, int y);
public: public:
Server_CardZone(Server_Player *_player, const QString &_name, bool _has_coords, ServerInfo_Zone::ZoneType _type); Server_CardZone(Server_Player *_player, const QString &_name, bool _has_coords, ServerInfo_Zone::ZoneType _type);
~Server_CardZone(); ~Server_CardZone();
const QList<Server_Card *> &getCards() const { return cards; } const QList<Server_Card *> &getCards() const { return cards; }
int removeCard(Server_Card *card); int removeCard(Server_Card *card);
Server_Card *getCard(int id, int *position = NULL, bool remove = false); Server_Card *getCard(int id, int *position = NULL, bool remove = false);
int getCardsBeingLookedAt() const { return cardsBeingLookedAt; } int getCardsBeingLookedAt() const { return cardsBeingLookedAt; }
void setCardsBeingLookedAt(int _cardsBeingLookedAt) { cardsBeingLookedAt = _cardsBeingLookedAt; } void setCardsBeingLookedAt(int _cardsBeingLookedAt) { cardsBeingLookedAt = _cardsBeingLookedAt; }
bool hasCoords() const { return has_coords; } bool hasCoords() const { return has_coords; }
ServerInfo_Zone::ZoneType getType() const { return type; } ServerInfo_Zone::ZoneType getType() const { return type; }
QString getName() const { return name; } QString getName() const { return name; }
Server_Player *getPlayer() const { return player; } Server_Player *getPlayer() const { return player; }
void getInfo(ServerInfo_Zone *info, Server_Player *playerWhosAsking, bool omniscient); void getInfo(ServerInfo_Zone *info, Server_Player *playerWhosAsking, bool omniscient);
int getFreeGridColumn(int x, int y, const QString &cardName) const; int getFreeGridColumn(int x, int y, const QString &cardName) const;
bool isColumnEmpty(int x, int y) const; bool isColumnEmpty(int x, int y) const;
bool isColumnStacked(int x, int y) const; bool isColumnStacked(int x, int y) const;
void fixFreeSpaces(GameEventStorage &ges); void fixFreeSpaces(GameEventStorage &ges);
void moveCardInRow(GameEventStorage &ges, Server_Card *card, int x, int y); void moveCardInRow(GameEventStorage &ges, Server_Card *card, int x, int y);
void insertCard(Server_Card *card, int x, int y); void insertCard(Server_Card *card, int x, int y);
void updateCardCoordinates(Server_Card *card, int oldX, int oldY); void updateCardCoordinates(Server_Card *card, int oldX, int oldY);
void shuffle(); void shuffle();
void clear(); void clear();
void addWritePermission(int playerId); void addWritePermission(int playerId);
const QSet<int> &getPlayersWithWritePermission() const { return playersWithWritePermission; } const QSet<int> &getPlayersWithWritePermission() const { return playersWithWritePermission; }
bool getAlwaysRevealTopCard() const { return alwaysRevealTopCard; } bool getAlwaysRevealTopCard() const { return alwaysRevealTopCard; }
void setAlwaysRevealTopCard(bool _alwaysRevealTopCard) { alwaysRevealTopCard = _alwaysRevealTopCard; } void setAlwaysRevealTopCard(bool _alwaysRevealTopCard) { alwaysRevealTopCard = _alwaysRevealTopCard; }
}; };
#endif #endif

View file

@ -12,9 +12,9 @@ Server_Counter::Server_Counter(int _id, const QString &_name, const color &_coun
void Server_Counter::getInfo(ServerInfo_Counter *info) void Server_Counter::getInfo(ServerInfo_Counter *info)
{ {
info->set_id(id); info->set_id(id);
info->set_name(name.toStdString()); info->set_name(name.toStdString());
info->mutable_counter_color()->CopyFrom(counterColor); info->mutable_counter_color()->CopyFrom(counterColor);
info->set_radius(radius); info->set_radius(radius);
info->set_count(count); info->set_count(count);
} }

View file

@ -27,22 +27,22 @@ class ServerInfo_Counter;
class Server_Counter { class Server_Counter {
protected: protected:
int id; int id;
QString name; QString name;
color counterColor; color counterColor;
int radius; int radius;
int count; int count;
public: public:
Server_Counter(int _id, const QString &_name, const color &_counterColor, int _radius, int _count = 0); Server_Counter(int _id, const QString &_name, const color &_counterColor, int _radius, int _count = 0);
~Server_Counter() { } ~Server_Counter() { }
int getId() const { return id; } int getId() const { return id; }
QString getName() const { return name; } QString getName() const { return name; }
const color &getColor() const { return counterColor; } const color &getColor() const { return counterColor; }
int getRadius() const { return radius; } int getRadius() const { return radius; }
int getCount() const { return count; } int getCount() const { return count; }
void setCount(int _count) { count = _count; } void setCount(int _count) { count = _count; }
void getInfo(ServerInfo_Counter *info); void getInfo(ServerInfo_Counter *info);
}; };
#endif #endif

View file

@ -6,32 +6,32 @@
#include "server.h" #include "server.h"
class Server_DatabaseInterface : public QObject { class Server_DatabaseInterface : public QObject {
Q_OBJECT Q_OBJECT
public: public:
Server_DatabaseInterface(QObject *parent = 0) Server_DatabaseInterface(QObject *parent = 0)
: QObject(parent) { } : QObject(parent) { }
virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &secondsLeft) = 0; virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &secondsLeft) = 0;
virtual bool userExists(const QString &user) { return false; } virtual bool userExists(const QString & /* user */) { return false; }
virtual QMap<QString, ServerInfo_User> getBuddyList(const QString &name) { return QMap<QString, ServerInfo_User>(); } virtual QMap<QString, ServerInfo_User> getBuddyList(const QString & /* name */) { return QMap<QString, ServerInfo_User>(); }
virtual QMap<QString, ServerInfo_User> getIgnoreList(const QString &name) { return QMap<QString, ServerInfo_User>(); } virtual QMap<QString, ServerInfo_User> getIgnoreList(const QString & /* name */) { return QMap<QString, ServerInfo_User>(); }
virtual bool isInBuddyList(const QString &whoseList, const QString &who) { return false; } virtual bool isInBuddyList(const QString & /* whoseList */, const QString & /* who */) { return false; }
virtual bool isInIgnoreList(const QString &whoseList, const QString &who) { return false; } virtual bool isInIgnoreList(const QString & /* whoseList */, const QString & /* who */) { return false; }
virtual ServerInfo_User getUserData(const QString &name, bool withId = false) = 0; virtual ServerInfo_User getUserData(const QString &name, bool withId = false) = 0;
virtual void storeGameInformation(const QString &roomName, const QStringList &roomGameTypes, const ServerInfo_Game &gameInfo, const QSet<QString> &allPlayersEver, const QSet<QString> &allSpectatorsEver, const QList<GameReplay *> &replayList) { } virtual void storeGameInformation(const QString & /* roomName */, const QStringList & /* roomGameTypes */, const ServerInfo_Game & /* gameInfo */, const QSet<QString> & /* allPlayersEver */, const QSet<QString> & /* allSpectatorsEver */, const QList<GameReplay *> & /* replayList */) { }
virtual DeckList *getDeckFromDatabase(int deckId, int userId) { return 0; } virtual DeckList *getDeckFromDatabase(int /* deckId */, int /* userId */) { return 0; }
virtual qint64 startSession(const QString &userName, const QString &address) { return 0; } virtual qint64 startSession(const QString & /* userName */, const QString & /* address */) { return 0; }
public slots: public slots:
virtual void endSession(qint64 sessionId) { } virtual void endSession(qint64 /* sessionId */ ) { }
public: public:
virtual int getNextGameId() = 0; virtual int getNextGameId() = 0;
virtual int getNextReplayId() = 0; virtual int getNextReplayId() = 0;
virtual void clearSessionTables() { } virtual void clearSessionTables() { }
virtual void lockSessionTables() { } virtual void lockSessionTables() { }
virtual void unlockSessionTables() { } virtual void unlockSessionTables() { }
virtual bool userSessionExists(const QString &userName) { return false; } virtual bool userSessionExists(const QString & /* userName */) { return false; }
}; };
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -42,86 +42,86 @@ class Server_AbstractUserInterface;
class Event_GameStateChanged; class Event_GameStateChanged;
class Server_Game : public QObject { class Server_Game : public QObject {
Q_OBJECT Q_OBJECT
private: private:
Server_Room *room; Server_Room *room;
int nextPlayerId; int nextPlayerId;
int hostId; int hostId;
ServerInfo_User *creatorInfo; ServerInfo_User *creatorInfo;
QMap<int, Server_Player *> players; QMap<int, Server_Player *> players;
QSet<QString> allPlayersEver, allSpectatorsEver; QSet<QString> allPlayersEver, allSpectatorsEver;
bool gameStarted; bool gameStarted;
bool gameClosed; bool gameClosed;
int gameId; int gameId;
QString description; QString description;
QString password; QString password;
int maxPlayers; int maxPlayers;
QList<int> gameTypes; QList<int> gameTypes;
int activePlayer, activePhase; int activePlayer, activePhase;
bool onlyBuddies, onlyRegistered; bool onlyBuddies, onlyRegistered;
bool spectatorsAllowed; bool spectatorsAllowed;
bool spectatorsNeedPassword; bool spectatorsNeedPassword;
bool spectatorsCanTalk; bool spectatorsCanTalk;
bool spectatorsSeeEverything; bool spectatorsSeeEverything;
int inactivityCounter; int inactivityCounter;
int startTimeOfThisGame, secondsElapsed; int startTimeOfThisGame, secondsElapsed;
bool firstGameStarted; bool firstGameStarted;
QDateTime startTime; QDateTime startTime;
QTimer *pingClock; QTimer *pingClock;
QList<GameReplay *> replayList; QList<GameReplay *> replayList;
GameReplay *currentReplay; GameReplay *currentReplay;
void createGameStateChangedEvent(Event_GameStateChanged *event, Server_Player *playerWhosAsking, bool omniscient, bool withUserInfo); void createGameStateChangedEvent(Event_GameStateChanged *event, Server_Player *playerWhosAsking, bool omniscient, bool withUserInfo);
void sendGameStateToPlayers(); void sendGameStateToPlayers();
void storeGameInformation(); void storeGameInformation();
signals: signals:
void sigStartGameIfReady(); void sigStartGameIfReady();
void gameInfoChanged(ServerInfo_Game gameInfo); void gameInfoChanged(ServerInfo_Game gameInfo);
private slots: private slots:
void pingClockTimeout(); void pingClockTimeout();
void doStartGameIfReady(); void doStartGameIfReady();
public: public:
mutable QMutex gameMutex; mutable QMutex gameMutex;
Server_Game(const ServerInfo_User &_creatorInfo, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, const QList<int> &_gameTypes, bool _onlyBuddies, bool _onlyRegistered, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server_Room *parent); Server_Game(const ServerInfo_User &_creatorInfo, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, const QList<int> &_gameTypes, bool _onlyBuddies, bool _onlyRegistered, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server_Room *parent);
~Server_Game(); ~Server_Game();
Server_Room *getRoom() const { return room; } Server_Room *getRoom() const { return room; }
void getInfo(ServerInfo_Game &result) const; void getInfo(ServerInfo_Game &result) const;
int getHostId() const { return hostId; } int getHostId() const { return hostId; }
ServerInfo_User *getCreatorInfo() const { return creatorInfo; } ServerInfo_User *getCreatorInfo() const { return creatorInfo; }
bool getGameStarted() const { return gameStarted; } bool getGameStarted() const { return gameStarted; }
int getPlayerCount() const; int getPlayerCount() const;
int getSpectatorCount() const; int getSpectatorCount() const;
const QMap<int, Server_Player *> &getPlayers() const { return players; } const QMap<int, Server_Player *> &getPlayers() const { return players; }
int getGameId() const { return gameId; } int getGameId() const { return gameId; }
QString getDescription() const { return description; } QString getDescription() const { return description; }
QString getPassword() const { return password; } QString getPassword() const { return password; }
int getMaxPlayers() const { return maxPlayers; } int getMaxPlayers() const { return maxPlayers; }
bool getSpectatorsAllowed() const { return spectatorsAllowed; } bool getSpectatorsAllowed() const { return spectatorsAllowed; }
bool getSpectatorsNeedPassword() const { return spectatorsNeedPassword; } bool getSpectatorsNeedPassword() const { return spectatorsNeedPassword; }
bool getSpectatorsCanTalk() const { return spectatorsCanTalk; } bool getSpectatorsCanTalk() const { return spectatorsCanTalk; }
bool getSpectatorsSeeEverything() const { return spectatorsSeeEverything; } bool getSpectatorsSeeEverything() const { return spectatorsSeeEverything; }
Response::ResponseCode checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions); Response::ResponseCode checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions);
bool containsUser(const QString &userName) const; bool containsUser(const QString &userName) const;
void addPlayer(Server_AbstractUserInterface *userInterface, ResponseContainer &rc, bool spectator, bool broadcastUpdate = true); void addPlayer(Server_AbstractUserInterface *userInterface, ResponseContainer &rc, bool spectator, bool broadcastUpdate = true);
void removePlayer(Server_Player *player); void removePlayer(Server_Player *player);
void removeArrowsRelatedToPlayer(GameEventStorage &ges, Server_Player *player); void removeArrowsRelatedToPlayer(GameEventStorage &ges, Server_Player *player);
void unattachCards(GameEventStorage &ges, Server_Player *player); void unattachCards(GameEventStorage &ges, Server_Player *player);
bool kickPlayer(int playerId); bool kickPlayer(int playerId);
void startGameIfReady(); void startGameIfReady();
void stopGameIfFinished(); void stopGameIfFinished();
int getActivePlayer() const { return activePlayer; } int getActivePlayer() const { return activePlayer; }
int getActivePhase() const { return activePhase; } int getActivePhase() const { return activePhase; }
void setActivePlayer(int _activePlayer); void setActivePlayer(int _activePlayer);
void setActivePhase(int _activePhase); void setActivePhase(int _activePhase);
void nextTurn(); void nextTurn();
int getSecondsElapsed() const { return secondsElapsed; } int getSecondsElapsed() const { return secondsElapsed; }
void createGameJoinedEvent(Server_Player *player, ResponseContainer &rc, bool resuming); void createGameJoinedEvent(Server_Player *player, ResponseContainer &rc, bool resuming);
GameEventContainer *prepareGameEvent(const ::google::protobuf::Message &gameEvent, int playerId, GameEventContext *context = 0); GameEventContainer *prepareGameEvent(const ::google::protobuf::Message &gameEvent, int playerId, GameEventContext *context = 0);
GameEventContext prepareGameEventContext(const ::google::protobuf::Message &gameEventContext); GameEventContext prepareGameEventContext(const ::google::protobuf::Message &gameEventContext);
void sendGameEventContainer(GameEventContainer *cont, GameEventStorageItem::EventRecipients recipients = GameEventStorageItem::SendToPrivate | GameEventStorageItem::SendToOthers, int privatePlayerId = -1); void sendGameEventContainer(GameEventContainer *cont, GameEventStorageItem::EventRecipients recipients = GameEventStorageItem::SendToPrivate | GameEventStorageItem::SendToOthers, int privatePlayerId = -1);
}; };
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -62,104 +62,104 @@ class Command_SetSideboardLock;
class Command_ChangeZoneProperties; class Command_ChangeZoneProperties;
class Server_Player : public Server_ArrowTarget, public ServerInfo_User_Container { class Server_Player : public Server_ArrowTarget, public ServerInfo_User_Container {
Q_OBJECT Q_OBJECT
private: private:
class MoveCardCompareFunctor; class MoveCardCompareFunctor;
Server_Game *game; Server_Game *game;
Server_AbstractUserInterface *userInterface; Server_AbstractUserInterface *userInterface;
DeckList *deck; DeckList *deck;
QMap<QString, Server_CardZone *> zones; QMap<QString, Server_CardZone *> zones;
QMap<int, Server_Counter *> counters; QMap<int, Server_Counter *> counters;
QMap<int, Server_Arrow *> arrows; QMap<int, Server_Arrow *> arrows;
QList<int> lastDrawList; QList<int> lastDrawList;
int pingTime; int pingTime;
int playerId; int playerId;
bool spectator; bool spectator;
int initialCards; int initialCards;
int nextCardId; int nextCardId;
bool readyStart; bool readyStart;
bool conceded; bool conceded;
bool sideboardLocked; bool sideboardLocked;
public: public:
mutable QMutex playerMutex; mutable QMutex playerMutex;
Server_Player(Server_Game *_game, int _playerId, const ServerInfo_User &_userInfo, bool _spectator, Server_AbstractUserInterface *_handler); Server_Player(Server_Game *_game, int _playerId, const ServerInfo_User &_userInfo, bool _spectator, Server_AbstractUserInterface *_handler);
~Server_Player(); ~Server_Player();
void prepareDestroy(); void prepareDestroy();
Server_AbstractUserInterface *getUserInterface() const { return userInterface; } Server_AbstractUserInterface *getUserInterface() const { return userInterface; }
void setUserInterface(Server_AbstractUserInterface *_userInterface); void setUserInterface(Server_AbstractUserInterface *_userInterface);
void disconnectClient(); void disconnectClient();
void setPlayerId(int _id) { playerId = _id; } void setPlayerId(int _id) { playerId = _id; }
bool getReadyStart() const { return readyStart; } bool getReadyStart() const { return readyStart; }
void setReadyStart(bool _readyStart) { readyStart = _readyStart; } void setReadyStart(bool _readyStart) { readyStart = _readyStart; }
int getPlayerId() const { return playerId; } int getPlayerId() const { return playerId; }
bool getSpectator() const { return spectator; } bool getSpectator() const { return spectator; }
bool getConceded() const { return conceded; } bool getConceded() const { return conceded; }
void setConceded(bool _conceded) { conceded = _conceded; } void setConceded(bool _conceded) { conceded = _conceded; }
DeckList *getDeck() const { return deck; } DeckList *getDeck() const { return deck; }
Server_Game *getGame() const { return game; } Server_Game *getGame() const { return game; }
const QMap<QString, Server_CardZone *> &getZones() const { return zones; } const QMap<QString, Server_CardZone *> &getZones() const { return zones; }
const QMap<int, Server_Counter *> &getCounters() const { return counters; } const QMap<int, Server_Counter *> &getCounters() const { return counters; }
const QMap<int, Server_Arrow *> &getArrows() const { return arrows; } const QMap<int, Server_Arrow *> &getArrows() const { return arrows; }
int getPingTime() const { return pingTime; } int getPingTime() const { return pingTime; }
void setPingTime(int _pingTime) { pingTime = _pingTime; } void setPingTime(int _pingTime) { pingTime = _pingTime; }
void getProperties(ServerInfo_PlayerProperties &result, bool withUserInfo); void getProperties(ServerInfo_PlayerProperties &result, bool withUserInfo);
int newCardId(); int newCardId();
int newCounterId() const; int newCounterId() const;
int newArrowId() const; int newArrowId() const;
void addZone(Server_CardZone *zone); void addZone(Server_CardZone *zone);
void addArrow(Server_Arrow *arrow); void addArrow(Server_Arrow *arrow);
bool deleteArrow(int arrowId); bool deleteArrow(int arrowId);
void addCounter(Server_Counter *counter); void addCounter(Server_Counter *counter);
void clearZones(); void clearZones();
void setupZones(); void setupZones();
Response::ResponseCode drawCards(GameEventStorage &ges, int number); Response::ResponseCode drawCards(GameEventStorage &ges, int number);
Response::ResponseCode moveCard(GameEventStorage &ges, Server_CardZone *startzone, const QList<const CardToMove *> &_cards, Server_CardZone *targetzone, int x, int y, bool fixFreeSpaces = true, bool undoingDraw = false); Response::ResponseCode moveCard(GameEventStorage &ges, Server_CardZone *startzone, const QList<const CardToMove *> &_cards, Server_CardZone *targetzone, int x, int y, bool fixFreeSpaces = true, bool undoingDraw = false);
void unattachCard(GameEventStorage &ges, Server_Card *card); void unattachCard(GameEventStorage &ges, Server_Card *card);
Response::ResponseCode setCardAttrHelper(GameEventStorage &ges, const QString &zone, int cardId, CardAttribute attribute, const QString &attrValue); Response::ResponseCode setCardAttrHelper(GameEventStorage &ges, const QString &zone, int cardId, CardAttribute attribute, const QString &attrValue);
Response::ResponseCode cmdLeaveGame(const Command_LeaveGame &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdLeaveGame(const Command_LeaveGame &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdKickFromGame(const Command_KickFromGame &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdKickFromGame(const Command_KickFromGame &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdConcede(const Command_Concede &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdConcede(const Command_Concede &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdReadyStart(const Command_ReadyStart &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdReadyStart(const Command_ReadyStart &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdDeckSelect(const Command_DeckSelect &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdDeckSelect(const Command_DeckSelect &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdSetSideboardPlan(const Command_SetSideboardPlan &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdSetSideboardPlan(const Command_SetSideboardPlan &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdSetSideboardLock(const Command_SetSideboardLock &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdSetSideboardLock(const Command_SetSideboardLock &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdGameSay(const Command_GameSay &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdGameSay(const Command_GameSay &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdShuffle(const Command_Shuffle &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdShuffle(const Command_Shuffle &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdMulligan(const Command_Mulligan &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdMulligan(const Command_Mulligan &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdRollDie(const Command_RollDie &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdRollDie(const Command_RollDie &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdDrawCards(const Command_DrawCards &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdDrawCards(const Command_DrawCards &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdUndoDraw(const Command_UndoDraw &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdUndoDraw(const Command_UndoDraw &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdMoveCard(const Command_MoveCard &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdMoveCard(const Command_MoveCard &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdFlipCard(const Command_FlipCard &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdFlipCard(const Command_FlipCard &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdAttachCard(const Command_AttachCard &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdAttachCard(const Command_AttachCard &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdCreateArrow(const Command_CreateArrow &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdCreateArrow(const Command_CreateArrow &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdDeleteArrow(const Command_DeleteArrow &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdDeleteArrow(const Command_DeleteArrow &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdSetCardAttr(const Command_SetCardAttr &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdSetCardAttr(const Command_SetCardAttr &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdSetCardCounter(const Command_SetCardCounter &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdSetCardCounter(const Command_SetCardCounter &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdIncCardCounter(const Command_IncCardCounter &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdIncCardCounter(const Command_IncCardCounter &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdIncCounter(const Command_IncCounter &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdIncCounter(const Command_IncCounter &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdCreateCounter(const Command_CreateCounter &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdCreateCounter(const Command_CreateCounter &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdSetCounter(const Command_SetCounter &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdSetCounter(const Command_SetCounter &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdDelCounter(const Command_DelCounter &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdDelCounter(const Command_DelCounter &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdNextTurn(const Command_NextTurn &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdNextTurn(const Command_NextTurn &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdSetActivePhase(const Command_SetActivePhase &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdSetActivePhase(const Command_SetActivePhase &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdDumpZone(const Command_DumpZone &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdDumpZone(const Command_DumpZone &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdStopDumpZone(const Command_StopDumpZone &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdStopDumpZone(const Command_StopDumpZone &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdRevealCards(const Command_RevealCards &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdRevealCards(const Command_RevealCards &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode cmdChangeZoneProperties(const Command_ChangeZoneProperties &cmd, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode cmdChangeZoneProperties(const Command_ChangeZoneProperties &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode processGameCommand(const GameCommand &command, ResponseContainer &rc, GameEventStorage &ges); Response::ResponseCode processGameCommand(const GameCommand &command, ResponseContainer &rc, GameEventStorage &ges);
void sendGameEvent(const GameEventContainer &event); void sendGameEvent(const GameEventContainer &event);
void getInfo(ServerInfo_Player *info, Server_Player *playerWhosAsking, bool omniscient, bool withUserInfo); void getInfo(ServerInfo_Player *info, Server_Player *playerWhosAsking, bool omniscient, bool withUserInfo);
}; };
#endif #endif

View file

@ -3,15 +3,15 @@
class PlayerReference { class PlayerReference {
private: private:
int roomId; int roomId;
int gameId; int gameId;
int playerId; int playerId;
public: public:
PlayerReference(int _roomId, int _gameId, int _playerId) : roomId(_roomId), gameId(_gameId), playerId(_playerId) { } PlayerReference(int _roomId, int _gameId, int _playerId) : roomId(_roomId), gameId(_gameId), playerId(_playerId) { }
int getRoomId() const { return roomId; } int getRoomId() const { return roomId; }
int getGameId() const { return gameId; } int getGameId() const { return gameId; }
int getPlayerId() const { return playerId; } int getPlayerId() const { return playerId; }
bool operator==(const PlayerReference &other) { return ((roomId == other.roomId) && (gameId == other.gameId) && (playerId == other.playerId)); } bool operator==(const PlayerReference &other) { return ((roomId == other.roomId) && (gameId == other.gameId) && (playerId == other.playerId)); }
}; };
#endif #endif

View file

@ -21,17 +21,17 @@
#include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.h>
Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, Server_DatabaseInterface *_databaseInterface, QObject *parent) Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, Server_DatabaseInterface *_databaseInterface, QObject *parent)
: QObject(parent), : QObject(parent),
Server_AbstractUserInterface(_server), Server_AbstractUserInterface(_server),
deleted(false), deleted(false),
databaseInterface(_databaseInterface), databaseInterface(_databaseInterface),
authState(NotLoggedIn), authState(NotLoggedIn),
acceptsUserListChanges(false), acceptsUserListChanges(false),
acceptsRoomListChanges(false), acceptsRoomListChanges(false),
timeRunning(0), timeRunning(0),
lastDataReceived(0) lastDataReceived(0)
{ {
connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout())); connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout()));
} }
Server_ProtocolHandler::~Server_ProtocolHandler() Server_ProtocolHandler::~Server_ProtocolHandler()
@ -42,540 +42,540 @@ Server_ProtocolHandler::~Server_ProtocolHandler()
// The thread must not hold any server locks when calling this (e.g. clientsLock, roomsLock). // The thread must not hold any server locks when calling this (e.g. clientsLock, roomsLock).
void Server_ProtocolHandler::prepareDestroy() void Server_ProtocolHandler::prepareDestroy()
{ {
if (deleted) if (deleted)
return; return;
deleted = true; deleted = true;
QMapIterator<int, Server_Room *> roomIterator(rooms); QMapIterator<int, Server_Room *> roomIterator(rooms);
while (roomIterator.hasNext()) while (roomIterator.hasNext())
roomIterator.next().value()->removeClient(this); roomIterator.next().value()->removeClient(this);
QMap<int, QPair<int, int> > tempGames(getGames()); QMap<int, QPair<int, int> > tempGames(getGames());
server->roomsLock.lockForRead(); server->roomsLock.lockForRead();
QMapIterator<int, QPair<int, int> > gameIterator(tempGames); QMapIterator<int, QPair<int, int> > gameIterator(tempGames);
while (gameIterator.hasNext()) { while (gameIterator.hasNext()) {
gameIterator.next(); gameIterator.next();
Server_Room *r = server->getRooms().value(gameIterator.value().first); Server_Room *r = server->getRooms().value(gameIterator.value().first);
if (!r) if (!r)
continue; continue;
r->gamesLock.lockForRead(); r->gamesLock.lockForRead();
Server_Game *g = r->getGames().value(gameIterator.key()); Server_Game *g = r->getGames().value(gameIterator.key());
if (!g) { if (!g) {
r->gamesLock.unlock(); r->gamesLock.unlock();
continue; continue;
} }
g->gameMutex.lock(); g->gameMutex.lock();
Server_Player *p = g->getPlayers().value(gameIterator.value().second); Server_Player *p = g->getPlayers().value(gameIterator.value().second);
if (!p) { if (!p) {
g->gameMutex.unlock(); g->gameMutex.unlock();
r->gamesLock.unlock(); r->gamesLock.unlock();
continue; continue;
} }
p->disconnectClient(); p->disconnectClient();
g->gameMutex.unlock(); g->gameMutex.unlock();
r->gamesLock.unlock(); r->gamesLock.unlock();
} }
server->roomsLock.unlock(); server->roomsLock.unlock();
server->removeClient(this); server->removeClient(this);
deleteLater(); deleteLater();
} }
void Server_ProtocolHandler::sendProtocolItem(const Response &item) void Server_ProtocolHandler::sendProtocolItem(const Response &item)
{ {
ServerMessage msg; ServerMessage msg;
msg.mutable_response()->CopyFrom(item); msg.mutable_response()->CopyFrom(item);
msg.set_message_type(ServerMessage::RESPONSE); msg.set_message_type(ServerMessage::RESPONSE);
transmitProtocolItem(msg); transmitProtocolItem(msg);
} }
void Server_ProtocolHandler::sendProtocolItem(const SessionEvent &item) void Server_ProtocolHandler::sendProtocolItem(const SessionEvent &item)
{ {
ServerMessage msg; ServerMessage msg;
msg.mutable_session_event()->CopyFrom(item); msg.mutable_session_event()->CopyFrom(item);
msg.set_message_type(ServerMessage::SESSION_EVENT); msg.set_message_type(ServerMessage::SESSION_EVENT);
transmitProtocolItem(msg); transmitProtocolItem(msg);
} }
void Server_ProtocolHandler::sendProtocolItem(const GameEventContainer &item) void Server_ProtocolHandler::sendProtocolItem(const GameEventContainer &item)
{ {
ServerMessage msg; ServerMessage msg;
msg.mutable_game_event_container()->CopyFrom(item); msg.mutable_game_event_container()->CopyFrom(item);
msg.set_message_type(ServerMessage::GAME_EVENT_CONTAINER); msg.set_message_type(ServerMessage::GAME_EVENT_CONTAINER);
transmitProtocolItem(msg); transmitProtocolItem(msg);
} }
void Server_ProtocolHandler::sendProtocolItem(const RoomEvent &item) void Server_ProtocolHandler::sendProtocolItem(const RoomEvent &item)
{ {
ServerMessage msg; ServerMessage msg;
msg.mutable_room_event()->CopyFrom(item); msg.mutable_room_event()->CopyFrom(item);
msg.set_message_type(ServerMessage::ROOM_EVENT); msg.set_message_type(ServerMessage::ROOM_EVENT);
transmitProtocolItem(msg); transmitProtocolItem(msg);
} }
Response::ResponseCode Server_ProtocolHandler::processSessionCommandContainer(const CommandContainer &cont, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::processSessionCommandContainer(const CommandContainer &cont, ResponseContainer &rc)
{ {
Response::ResponseCode finalResponseCode = Response::RespOk; Response::ResponseCode finalResponseCode = Response::RespOk;
for (int i = cont.session_command_size() - 1; i >= 0; --i) { for (int i = cont.session_command_size() - 1; i >= 0; --i) {
Response::ResponseCode resp = Response::RespInvalidCommand; Response::ResponseCode resp = Response::RespInvalidCommand;
const SessionCommand &sc = cont.session_command(i); const SessionCommand &sc = cont.session_command(i);
const int num = getPbExtension(sc); const int num = getPbExtension(sc);
if (num != SessionCommand::PING) { // don't log ping commands if (num != SessionCommand::PING) { // don't log ping commands
if (num == SessionCommand::LOGIN) { // log login commands, but hide passwords if (num == SessionCommand::LOGIN) { // log login commands, but hide passwords
SessionCommand debugSc(sc); SessionCommand debugSc(sc);
debugSc.MutableExtension(Command_Login::ext)->clear_password(); debugSc.MutableExtension(Command_Login::ext)->clear_password();
logDebugMessage(QString::fromStdString(debugSc.ShortDebugString())); logDebugMessage(QString::fromStdString(debugSc.ShortDebugString()));
} else } else
logDebugMessage(QString::fromStdString(sc.ShortDebugString())); logDebugMessage(QString::fromStdString(sc.ShortDebugString()));
} }
switch ((SessionCommand::SessionCommandType) num) { switch ((SessionCommand::SessionCommandType) num) {
case SessionCommand::PING: resp = cmdPing(sc.GetExtension(Command_Ping::ext), rc); break; case SessionCommand::PING: resp = cmdPing(sc.GetExtension(Command_Ping::ext), rc); break;
case SessionCommand::LOGIN: resp = cmdLogin(sc.GetExtension(Command_Login::ext), rc); break; case SessionCommand::LOGIN: resp = cmdLogin(sc.GetExtension(Command_Login::ext), rc); break;
case SessionCommand::MESSAGE: resp = cmdMessage(sc.GetExtension(Command_Message::ext), rc); break; case SessionCommand::MESSAGE: resp = cmdMessage(sc.GetExtension(Command_Message::ext), rc); break;
case SessionCommand::GET_GAMES_OF_USER: resp = cmdGetGamesOfUser(sc.GetExtension(Command_GetGamesOfUser::ext), rc); break; case SessionCommand::GET_GAMES_OF_USER: resp = cmdGetGamesOfUser(sc.GetExtension(Command_GetGamesOfUser::ext), rc); break;
case SessionCommand::GET_USER_INFO: resp = cmdGetUserInfo(sc.GetExtension(Command_GetUserInfo::ext), rc); break; case SessionCommand::GET_USER_INFO: resp = cmdGetUserInfo(sc.GetExtension(Command_GetUserInfo::ext), rc); break;
case SessionCommand::LIST_ROOMS: resp = cmdListRooms(sc.GetExtension(Command_ListRooms::ext), rc); break; case SessionCommand::LIST_ROOMS: resp = cmdListRooms(sc.GetExtension(Command_ListRooms::ext), rc); break;
case SessionCommand::JOIN_ROOM: resp = cmdJoinRoom(sc.GetExtension(Command_JoinRoom::ext), rc); break; case SessionCommand::JOIN_ROOM: resp = cmdJoinRoom(sc.GetExtension(Command_JoinRoom::ext), rc); break;
case SessionCommand::LIST_USERS: resp = cmdListUsers(sc.GetExtension(Command_ListUsers::ext), rc); break; case SessionCommand::LIST_USERS: resp = cmdListUsers(sc.GetExtension(Command_ListUsers::ext), rc); break;
default: resp = processExtendedSessionCommand(num, sc, rc); default: resp = processExtendedSessionCommand(num, sc, rc);
} }
if (resp != Response::RespOk) if (resp != Response::RespOk)
finalResponseCode = resp; finalResponseCode = resp;
} }
return finalResponseCode; return finalResponseCode;
} }
Response::ResponseCode Server_ProtocolHandler::processRoomCommandContainer(const CommandContainer &cont, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::processRoomCommandContainer(const CommandContainer &cont, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
QReadLocker locker(&server->roomsLock); QReadLocker locker(&server->roomsLock);
Server_Room *room = rooms.value(cont.room_id(), 0); Server_Room *room = rooms.value(cont.room_id(), 0);
if (!room) if (!room)
return Response::RespNotInRoom; return Response::RespNotInRoom;
Response::ResponseCode finalResponseCode = Response::RespOk; Response::ResponseCode finalResponseCode = Response::RespOk;
for (int i = cont.room_command_size() - 1; i >= 0; --i) { for (int i = cont.room_command_size() - 1; i >= 0; --i) {
Response::ResponseCode resp = Response::RespInvalidCommand; Response::ResponseCode resp = Response::RespInvalidCommand;
const RoomCommand &sc = cont.room_command(i); const RoomCommand &sc = cont.room_command(i);
const int num = getPbExtension(sc); const int num = getPbExtension(sc);
logDebugMessage(QString::fromStdString(sc.ShortDebugString())); logDebugMessage(QString::fromStdString(sc.ShortDebugString()));
switch ((RoomCommand::RoomCommandType) num) { switch ((RoomCommand::RoomCommandType) num) {
case RoomCommand::LEAVE_ROOM: resp = cmdLeaveRoom(sc.GetExtension(Command_LeaveRoom::ext), room, rc); break; case RoomCommand::LEAVE_ROOM: resp = cmdLeaveRoom(sc.GetExtension(Command_LeaveRoom::ext), room, rc); break;
case RoomCommand::ROOM_SAY: resp = cmdRoomSay(sc.GetExtension(Command_RoomSay::ext), room, rc); break; case RoomCommand::ROOM_SAY: resp = cmdRoomSay(sc.GetExtension(Command_RoomSay::ext), room, rc); break;
case RoomCommand::CREATE_GAME: resp = cmdCreateGame(sc.GetExtension(Command_CreateGame::ext), room, rc); break; case RoomCommand::CREATE_GAME: resp = cmdCreateGame(sc.GetExtension(Command_CreateGame::ext), room, rc); break;
case RoomCommand::JOIN_GAME: resp = cmdJoinGame(sc.GetExtension(Command_JoinGame::ext), room, rc); break; case RoomCommand::JOIN_GAME: resp = cmdJoinGame(sc.GetExtension(Command_JoinGame::ext), room, rc); break;
} }
if (resp != Response::RespOk) if (resp != Response::RespOk)
finalResponseCode = resp; finalResponseCode = resp;
} }
return finalResponseCode; return finalResponseCode;
} }
Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const CommandContainer &cont, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const CommandContainer &cont, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
QMap<int, QPair<int, int> > gameMap = getGames(); QMap<int, QPair<int, int> > gameMap = getGames();
if (!gameMap.contains(cont.game_id())) if (!gameMap.contains(cont.game_id()))
return Response::RespNotInRoom; return Response::RespNotInRoom;
const QPair<int, int> roomIdAndPlayerId = gameMap.value(cont.game_id()); const QPair<int, int> roomIdAndPlayerId = gameMap.value(cont.game_id());
QReadLocker roomsLocker(&server->roomsLock); QReadLocker roomsLocker(&server->roomsLock);
Server_Room *room = server->getRooms().value(roomIdAndPlayerId.first); Server_Room *room = server->getRooms().value(roomIdAndPlayerId.first);
if (!room) if (!room)
return Response::RespNotInRoom; return Response::RespNotInRoom;
QReadLocker roomGamesLocker(&room->gamesLock); QReadLocker roomGamesLocker(&room->gamesLock);
Server_Game *game = room->getGames().value(cont.game_id()); Server_Game *game = room->getGames().value(cont.game_id());
if (!game) { if (!game) {
if (room->getExternalGames().contains(cont.game_id())) { if (room->getExternalGames().contains(cont.game_id())) {
server->sendIsl_GameCommand(cont, server->sendIsl_GameCommand(cont,
room->getExternalGames().value(cont.game_id()).server_id(), room->getExternalGames().value(cont.game_id()).server_id(),
userInfo->session_id(), userInfo->session_id(),
roomIdAndPlayerId.first, roomIdAndPlayerId.first,
roomIdAndPlayerId.second roomIdAndPlayerId.second
); );
return Response::RespNothing; return Response::RespNothing;
} }
return Response::RespNotInRoom; return Response::RespNotInRoom;
} }
QMutexLocker gameLocker(&game->gameMutex); QMutexLocker gameLocker(&game->gameMutex);
Server_Player *player = game->getPlayers().value(roomIdAndPlayerId.second); Server_Player *player = game->getPlayers().value(roomIdAndPlayerId.second);
if (!player) if (!player)
return Response::RespNotInRoom; return Response::RespNotInRoom;
GameEventStorage ges; GameEventStorage ges;
Response::ResponseCode finalResponseCode = Response::RespOk; Response::ResponseCode finalResponseCode = Response::RespOk;
for (int i = cont.game_command_size() - 1; i >= 0; --i) { for (int i = cont.game_command_size() - 1; i >= 0; --i) {
const GameCommand &sc = cont.game_command(i); const GameCommand &sc = cont.game_command(i);
logDebugMessage(QString("game %1 player %2: ").arg(cont.game_id()).arg(roomIdAndPlayerId.second) + QString::fromStdString(sc.ShortDebugString())); logDebugMessage(QString("game %1 player %2: ").arg(cont.game_id()).arg(roomIdAndPlayerId.second) + QString::fromStdString(sc.ShortDebugString()));
Response::ResponseCode resp = player->processGameCommand(sc, rc, ges); Response::ResponseCode resp = player->processGameCommand(sc, rc, ges);
if (resp != Response::RespOk) if (resp != Response::RespOk)
finalResponseCode = resp; finalResponseCode = resp;
} }
ges.sendToGame(game); ges.sendToGame(game);
return finalResponseCode; return finalResponseCode;
} }
Response::ResponseCode Server_ProtocolHandler::processModeratorCommandContainer(const CommandContainer &cont, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::processModeratorCommandContainer(const CommandContainer &cont, ResponseContainer &rc)
{ {
if (!userInfo) if (!userInfo)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
if (!(userInfo->user_level() & ServerInfo_User::IsModerator)) if (!(userInfo->user_level() & ServerInfo_User::IsModerator))
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
Response::ResponseCode finalResponseCode = Response::RespOk; Response::ResponseCode finalResponseCode = Response::RespOk;
for (int i = cont.moderator_command_size() - 1; i >= 0; --i) { for (int i = cont.moderator_command_size() - 1; i >= 0; --i) {
Response::ResponseCode resp = Response::RespInvalidCommand; Response::ResponseCode resp = Response::RespInvalidCommand;
const ModeratorCommand &sc = cont.moderator_command(i); const ModeratorCommand &sc = cont.moderator_command(i);
const int num = getPbExtension(sc); const int num = getPbExtension(sc);
logDebugMessage(QString::fromStdString(sc.ShortDebugString())); logDebugMessage(QString::fromStdString(sc.ShortDebugString()));
resp = processExtendedModeratorCommand(num, sc, rc); resp = processExtendedModeratorCommand(num, sc, rc);
if (resp != Response::RespOk) if (resp != Response::RespOk)
finalResponseCode = resp; finalResponseCode = resp;
} }
return finalResponseCode; return finalResponseCode;
} }
Response::ResponseCode Server_ProtocolHandler::processAdminCommandContainer(const CommandContainer &cont, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::processAdminCommandContainer(const CommandContainer &cont, ResponseContainer &rc)
{ {
if (!userInfo) if (!userInfo)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
if (!(userInfo->user_level() & ServerInfo_User::IsAdmin)) if (!(userInfo->user_level() & ServerInfo_User::IsAdmin))
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
Response::ResponseCode finalResponseCode = Response::RespOk; Response::ResponseCode finalResponseCode = Response::RespOk;
for (int i = cont.admin_command_size() - 1; i >= 0; --i) { for (int i = cont.admin_command_size() - 1; i >= 0; --i) {
Response::ResponseCode resp = Response::RespInvalidCommand; Response::ResponseCode resp = Response::RespInvalidCommand;
const AdminCommand &sc = cont.admin_command(i); const AdminCommand &sc = cont.admin_command(i);
const int num = getPbExtension(sc); const int num = getPbExtension(sc);
logDebugMessage(QString::fromStdString(sc.ShortDebugString())); logDebugMessage(QString::fromStdString(sc.ShortDebugString()));
resp = processExtendedAdminCommand(num, sc, rc); resp = processExtendedAdminCommand(num, sc, rc);
if (resp != Response::RespOk) if (resp != Response::RespOk)
finalResponseCode = resp; finalResponseCode = resp;
} }
return finalResponseCode; return finalResponseCode;
} }
void Server_ProtocolHandler::processCommandContainer(const CommandContainer &cont) void Server_ProtocolHandler::processCommandContainer(const CommandContainer &cont)
{ {
// Command processing must be disabled after prepareDestroy() has been called. // Command processing must be disabled after prepareDestroy() has been called.
if (deleted) if (deleted)
return; return;
lastDataReceived = timeRunning; lastDataReceived = timeRunning;
ResponseContainer responseContainer(cont.has_cmd_id() ? cont.cmd_id() : -1); ResponseContainer responseContainer(cont.has_cmd_id() ? cont.cmd_id() : -1);
Response::ResponseCode finalResponseCode; Response::ResponseCode finalResponseCode;
if (cont.game_command_size()) if (cont.game_command_size())
finalResponseCode = processGameCommandContainer(cont, responseContainer); finalResponseCode = processGameCommandContainer(cont, responseContainer);
else if (cont.room_command_size()) else if (cont.room_command_size())
finalResponseCode = processRoomCommandContainer(cont, responseContainer); finalResponseCode = processRoomCommandContainer(cont, responseContainer);
else if (cont.session_command_size()) else if (cont.session_command_size())
finalResponseCode = processSessionCommandContainer(cont, responseContainer); finalResponseCode = processSessionCommandContainer(cont, responseContainer);
else if (cont.moderator_command_size()) else if (cont.moderator_command_size())
finalResponseCode = processModeratorCommandContainer(cont, responseContainer); finalResponseCode = processModeratorCommandContainer(cont, responseContainer);
else if (cont.admin_command_size()) else if (cont.admin_command_size())
finalResponseCode = processAdminCommandContainer(cont, responseContainer); finalResponseCode = processAdminCommandContainer(cont, responseContainer);
else else
finalResponseCode = Response::RespInvalidCommand; finalResponseCode = Response::RespInvalidCommand;
if ((finalResponseCode != Response::RespNothing)) if ((finalResponseCode != Response::RespNothing))
sendResponseContainer(responseContainer, finalResponseCode); sendResponseContainer(responseContainer, finalResponseCode);
} }
void Server_ProtocolHandler::pingClockTimeout() void Server_ProtocolHandler::pingClockTimeout()
{ {
int interval = server->getMessageCountingInterval(); int interval = server->getMessageCountingInterval();
if (interval > 0) { if (interval > 0) {
messageSizeOverTime.prepend(0); messageSizeOverTime.prepend(0);
if (messageSizeOverTime.size() > server->getMessageCountingInterval()) if (messageSizeOverTime.size() > server->getMessageCountingInterval())
messageSizeOverTime.removeLast(); messageSizeOverTime.removeLast();
messageCountOverTime.prepend(0); messageCountOverTime.prepend(0);
if (messageCountOverTime.size() > server->getMessageCountingInterval()) if (messageCountOverTime.size() > server->getMessageCountingInterval())
messageCountOverTime.removeLast(); messageCountOverTime.removeLast();
} }
if (timeRunning - lastDataReceived > server->getMaxPlayerInactivityTime()) if (timeRunning - lastDataReceived > server->getMaxPlayerInactivityTime())
prepareDestroy(); prepareDestroy();
++timeRunning; ++timeRunning;
} }
Response::ResponseCode Server_ProtocolHandler::cmdPing(const Command_Ping & /*cmd*/, ResponseContainer & /*rc*/) Response::ResponseCode Server_ProtocolHandler::cmdPing(const Command_Ping & /*cmd*/, ResponseContainer & /*rc*/)
{ {
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd, ResponseContainer &rc)
{ {
QString userName = QString::fromStdString(cmd.user_name()).simplified(); QString userName = QString::fromStdString(cmd.user_name()).simplified();
if (userName.isEmpty() || (userInfo != 0)) if (userName.isEmpty() || (userInfo != 0))
return Response::RespContextError; return Response::RespContextError;
QString reasonStr; QString reasonStr;
int banSecondsLeft = 0; int banSecondsLeft = 0;
AuthenticationResult res = server->loginUser(this, userName, QString::fromStdString(cmd.password()), reasonStr, banSecondsLeft); AuthenticationResult res = server->loginUser(this, userName, QString::fromStdString(cmd.password()), reasonStr, banSecondsLeft);
switch (res) { switch (res) {
case UserIsBanned: { case UserIsBanned: {
Response_Login *re = new Response_Login; Response_Login *re = new Response_Login;
re->set_denied_reason_str(reasonStr.toStdString()); re->set_denied_reason_str(reasonStr.toStdString());
if (banSecondsLeft != 0) if (banSecondsLeft != 0)
re->set_denied_end_time(QDateTime::currentDateTime().addSecs(banSecondsLeft).toTime_t()); re->set_denied_end_time(QDateTime::currentDateTime().addSecs(banSecondsLeft).toTime_t());
rc.setResponseExtension(re); rc.setResponseExtension(re);
return Response::RespUserIsBanned; return Response::RespUserIsBanned;
} }
case NotLoggedIn: return Response::RespWrongPassword; case NotLoggedIn: return Response::RespWrongPassword;
case WouldOverwriteOldSession: return Response::RespWouldOverwriteOldSession; case WouldOverwriteOldSession: return Response::RespWouldOverwriteOldSession;
case UsernameInvalid: return Response::RespUsernameInvalid; case UsernameInvalid: return Response::RespUsernameInvalid;
default: authState = res; default: authState = res;
} }
userName = QString::fromStdString(userInfo->name()); userName = QString::fromStdString(userInfo->name());
Event_ServerMessage event; Event_ServerMessage event;
event.set_message(server->getLoginMessage().toStdString()); event.set_message(server->getLoginMessage().toStdString());
rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event)); rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event));
Response_Login *re = new Response_Login; Response_Login *re = new Response_Login;
re->mutable_user_info()->CopyFrom(copyUserInfo(true)); re->mutable_user_info()->CopyFrom(copyUserInfo(true));
if (authState == PasswordRight) { if (authState == PasswordRight) {
QMapIterator<QString, ServerInfo_User> buddyIterator(databaseInterface->getBuddyList(userName)); QMapIterator<QString, ServerInfo_User> buddyIterator(databaseInterface->getBuddyList(userName));
while (buddyIterator.hasNext()) while (buddyIterator.hasNext())
re->add_buddy_list()->CopyFrom(buddyIterator.next().value()); re->add_buddy_list()->CopyFrom(buddyIterator.next().value());
QMapIterator<QString, ServerInfo_User> ignoreIterator(databaseInterface->getIgnoreList(userName)); QMapIterator<QString, ServerInfo_User> ignoreIterator(databaseInterface->getIgnoreList(userName));
while (ignoreIterator.hasNext()) while (ignoreIterator.hasNext())
re->add_ignore_list()->CopyFrom(ignoreIterator.next().value()); re->add_ignore_list()->CopyFrom(ignoreIterator.next().value());
} }
joinPersistentGames(rc); joinPersistentGames(rc);
rc.setResponseExtension(re); rc.setResponseExtension(re);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdMessage(const Command_Message &cmd, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdMessage(const Command_Message &cmd, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
QReadLocker locker(&server->clientsLock); QReadLocker locker(&server->clientsLock);
QString receiver = QString::fromStdString(cmd.user_name()); QString receiver = QString::fromStdString(cmd.user_name());
Server_AbstractUserInterface *userInterface = server->findUser(receiver); Server_AbstractUserInterface *userInterface = server->findUser(receiver);
if (!userInterface) if (!userInterface)
return Response::RespNameNotFound; return Response::RespNameNotFound;
if (databaseInterface->isInIgnoreList(receiver, QString::fromStdString(userInfo->name()))) if (databaseInterface->isInIgnoreList(receiver, QString::fromStdString(userInfo->name())))
return Response::RespInIgnoreList; return Response::RespInIgnoreList;
Event_UserMessage event; Event_UserMessage event;
event.set_sender_name(userInfo->name()); event.set_sender_name(userInfo->name());
event.set_receiver_name(cmd.user_name()); event.set_receiver_name(cmd.user_name());
event.set_message(cmd.message()); event.set_message(cmd.message());
SessionEvent *se = prepareSessionEvent(event); SessionEvent *se = prepareSessionEvent(event);
userInterface->sendProtocolItem(*se); userInterface->sendProtocolItem(*se);
rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, se); rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, se);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdGetGamesOfUser(const Command_GetGamesOfUser &cmd, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdGetGamesOfUser(const Command_GetGamesOfUser &cmd, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
// We don't need to check whether the user is logged in; persistent games should also work. // We don't need to check whether the user is logged in; persistent games should also work.
// The client needs to deal with an empty result list. // The client needs to deal with an empty result list.
Response_GetGamesOfUser *re = new Response_GetGamesOfUser; Response_GetGamesOfUser *re = new Response_GetGamesOfUser;
server->roomsLock.lockForRead(); server->roomsLock.lockForRead();
QMapIterator<int, Server_Room *> roomIterator(server->getRooms()); QMapIterator<int, Server_Room *> roomIterator(server->getRooms());
while (roomIterator.hasNext()) { while (roomIterator.hasNext()) {
Server_Room *room = roomIterator.next().value(); Server_Room *room = roomIterator.next().value();
room->gamesLock.lockForRead(); room->gamesLock.lockForRead();
room->getInfo(*re->add_room_list(), false, true); room->getInfo(*re->add_room_list(), false, true);
QListIterator<ServerInfo_Game> gameIterator(room->getGamesOfUser(QString::fromStdString(cmd.user_name()))); QListIterator<ServerInfo_Game> gameIterator(room->getGamesOfUser(QString::fromStdString(cmd.user_name())));
while (gameIterator.hasNext()) while (gameIterator.hasNext())
re->add_game_list()->CopyFrom(gameIterator.next()); re->add_game_list()->CopyFrom(gameIterator.next());
room->gamesLock.unlock(); room->gamesLock.unlock();
} }
server->roomsLock.unlock(); server->roomsLock.unlock();
rc.setResponseExtension(re); rc.setResponseExtension(re);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdGetUserInfo(const Command_GetUserInfo &cmd, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdGetUserInfo(const Command_GetUserInfo &cmd, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
QString userName = QString::fromStdString(cmd.user_name()); QString userName = QString::fromStdString(cmd.user_name());
Response_GetUserInfo *re = new Response_GetUserInfo; Response_GetUserInfo *re = new Response_GetUserInfo;
if (userName.isEmpty()) if (userName.isEmpty())
re->mutable_user_info()->CopyFrom(*userInfo); re->mutable_user_info()->CopyFrom(*userInfo);
else { else {
QReadLocker locker(&server->clientsLock); QReadLocker locker(&server->clientsLock);
ServerInfo_User_Container *infoSource = server->findUser(userName); ServerInfo_User_Container *infoSource = server->findUser(userName);
if (!infoSource) if (!infoSource)
return Response::RespNameNotFound; return Response::RespNameNotFound;
re->mutable_user_info()->CopyFrom(infoSource->copyUserInfo(true, false, userInfo->user_level() & ServerInfo_User::IsModerator)); re->mutable_user_info()->CopyFrom(infoSource->copyUserInfo(true, false, userInfo->user_level() & ServerInfo_User::IsModerator));
} }
rc.setResponseExtension(re); rc.setResponseExtension(re);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdListRooms(const Command_ListRooms & /*cmd*/, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdListRooms(const Command_ListRooms & /*cmd*/, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
Event_ListRooms event; Event_ListRooms event;
QMapIterator<int, Server_Room *> roomIterator(server->getRooms()); QMapIterator<int, Server_Room *> roomIterator(server->getRooms());
while (roomIterator.hasNext()) while (roomIterator.hasNext())
roomIterator.next().value()->getInfo(*event.add_room_list(), false); roomIterator.next().value()->getInfo(*event.add_room_list(), false);
rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event)); rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event));
acceptsRoomListChanges = true; acceptsRoomListChanges = true;
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdJoinRoom(const Command_JoinRoom &cmd, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdJoinRoom(const Command_JoinRoom &cmd, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
if (rooms.contains(cmd.room_id())) if (rooms.contains(cmd.room_id()))
return Response::RespContextError; return Response::RespContextError;
QReadLocker serverLocker(&server->roomsLock); QReadLocker serverLocker(&server->roomsLock);
Server_Room *r = server->getRooms().value(cmd.room_id(), 0); Server_Room *r = server->getRooms().value(cmd.room_id(), 0);
if (!r) if (!r)
return Response::RespNameNotFound; return Response::RespNameNotFound;
r->addClient(this); r->addClient(this);
rooms.insert(r->getId(), r); rooms.insert(r->getId(), r);
Event_RoomSay joinMessageEvent; Event_RoomSay joinMessageEvent;
joinMessageEvent.set_message(r->getJoinMessage().toStdString()); joinMessageEvent.set_message(r->getJoinMessage().toStdString());
rc.enqueuePostResponseItem(ServerMessage::ROOM_EVENT, r->prepareRoomEvent(joinMessageEvent)); rc.enqueuePostResponseItem(ServerMessage::ROOM_EVENT, r->prepareRoomEvent(joinMessageEvent));
Response_JoinRoom *re = new Response_JoinRoom; Response_JoinRoom *re = new Response_JoinRoom;
r->getInfo(*re->mutable_room_info(), true); r->getInfo(*re->mutable_room_info(), true);
rc.setResponseExtension(re); rc.setResponseExtension(re);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdListUsers(const Command_ListUsers & /*cmd*/, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdListUsers(const Command_ListUsers & /*cmd*/, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
Response_ListUsers *re = new Response_ListUsers; Response_ListUsers *re = new Response_ListUsers;
server->clientsLock.lockForRead(); server->clientsLock.lockForRead();
QMapIterator<QString, Server_ProtocolHandler *> userIterator = server->getUsers(); QMapIterator<QString, Server_ProtocolHandler *> userIterator = server->getUsers();
while (userIterator.hasNext()) while (userIterator.hasNext())
re->add_user_list()->CopyFrom(userIterator.next().value()->copyUserInfo(false)); re->add_user_list()->CopyFrom(userIterator.next().value()->copyUserInfo(false));
QMapIterator<QString, Server_AbstractUserInterface *> extIterator = server->getExternalUsers(); QMapIterator<QString, Server_AbstractUserInterface *> extIterator = server->getExternalUsers();
while (extIterator.hasNext()) while (extIterator.hasNext())
re->add_user_list()->CopyFrom(extIterator.next().value()->copyUserInfo(false)); re->add_user_list()->CopyFrom(extIterator.next().value()->copyUserInfo(false));
acceptsUserListChanges = true; acceptsUserListChanges = true;
server->clientsLock.unlock(); server->clientsLock.unlock();
rc.setResponseExtension(re); rc.setResponseExtension(re);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdLeaveRoom(const Command_LeaveRoom & /*cmd*/, Server_Room *room, ResponseContainer & /*rc*/) Response::ResponseCode Server_ProtocolHandler::cmdLeaveRoom(const Command_LeaveRoom & /*cmd*/, Server_Room *room, ResponseContainer & /*rc*/)
{ {
rooms.remove(room->getId()); rooms.remove(room->getId());
room->removeClient(this); room->removeClient(this);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdRoomSay(const Command_RoomSay &cmd, Server_Room *room, ResponseContainer & /*rc*/) Response::ResponseCode Server_ProtocolHandler::cmdRoomSay(const Command_RoomSay &cmd, Server_Room *room, ResponseContainer & /*rc*/)
{ {
QString msg = QString::fromStdString(cmd.message()); QString msg = QString::fromStdString(cmd.message());
if (server->getMessageCountingInterval() > 0) { if (server->getMessageCountingInterval() > 0) {
int totalSize = 0, totalCount = 0; int totalSize = 0, totalCount = 0;
if (messageSizeOverTime.isEmpty()) if (messageSizeOverTime.isEmpty())
messageSizeOverTime.prepend(0); messageSizeOverTime.prepend(0);
messageSizeOverTime[0] += msg.size(); messageSizeOverTime[0] += msg.size();
for (int i = 0; i < messageSizeOverTime.size(); ++i) for (int i = 0; i < messageSizeOverTime.size(); ++i)
totalSize += messageSizeOverTime[i]; totalSize += messageSizeOverTime[i];
if (messageCountOverTime.isEmpty()) if (messageCountOverTime.isEmpty())
messageCountOverTime.prepend(0); messageCountOverTime.prepend(0);
++messageCountOverTime[0]; ++messageCountOverTime[0];
for (int i = 0; i < messageCountOverTime.size(); ++i) for (int i = 0; i < messageCountOverTime.size(); ++i)
totalCount += messageCountOverTime[i]; totalCount += messageCountOverTime[i];
if ((totalSize > server->getMaxMessageSizePerInterval()) || (totalCount > server->getMaxMessageCountPerInterval())) if ((totalSize > server->getMaxMessageSizePerInterval()) || (totalCount > server->getMaxMessageCountPerInterval()))
return Response::RespChatFlood; return Response::RespChatFlood;
} }
msg.replace(QChar('\n'), QChar(' ')); msg.replace(QChar('\n'), QChar(' '));
room->say(QString::fromStdString(userInfo->name()), msg); room->say(QString::fromStdString(userInfo->name()), msg);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdCreateGame(const Command_CreateGame &cmd, Server_Room *room, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdCreateGame(const Command_CreateGame &cmd, Server_Room *room, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
const int gameId = databaseInterface->getNextGameId(); const int gameId = databaseInterface->getNextGameId();
if (gameId == -1) if (gameId == -1)
return Response::RespInternalError; return Response::RespInternalError;
if (server->getMaxGamesPerUser() > 0) if (server->getMaxGamesPerUser() > 0)
if (room->getGamesCreatedByUser(QString::fromStdString(userInfo->name())) >= server->getMaxGamesPerUser()) if (room->getGamesCreatedByUser(QString::fromStdString(userInfo->name())) >= server->getMaxGamesPerUser())
return Response::RespContextError; return Response::RespContextError;
QList<int> gameTypes; QList<int> gameTypes;
for (int i = cmd.game_type_ids_size() - 1; i >= 0; --i) for (int i = cmd.game_type_ids_size() - 1; i >= 0; --i)
gameTypes.append(cmd.game_type_ids(i)); gameTypes.append(cmd.game_type_ids(i));
QString description = QString::fromStdString(cmd.description()); QString description = QString::fromStdString(cmd.description());
if (description.size() > 60) if (description.size() > 60)
description = description.left(60); description = description.left(60);
Server_Game *game = new Server_Game(copyUserInfo(false), gameId, description, QString::fromStdString(cmd.password()), cmd.max_players(), gameTypes, cmd.only_buddies(), cmd.only_registered(), cmd.spectators_allowed(), cmd.spectators_need_password(), cmd.spectators_can_talk(), cmd.spectators_see_everything(), room); Server_Game *game = new Server_Game(copyUserInfo(false), gameId, description, QString::fromStdString(cmd.password()), cmd.max_players(), gameTypes, cmd.only_buddies(), cmd.only_registered(), cmd.spectators_allowed(), cmd.spectators_need_password(), cmd.spectators_can_talk(), cmd.spectators_see_everything(), room);
game->addPlayer(this, rc, false, false); game->addPlayer(this, rc, false, false);
room->addGame(game); room->addGame(game);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGame &cmd, Server_Room *room, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGame &cmd, Server_Room *room, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
return room->processJoinGameCommand(cmd, rc, this); return room->processJoinGameCommand(cmd, rc, this);
} }

View file

@ -40,64 +40,64 @@ class Command_CreateGame;
class Command_JoinGame; class Command_JoinGame;
class Server_ProtocolHandler : public QObject, public Server_AbstractUserInterface { class Server_ProtocolHandler : public QObject, public Server_AbstractUserInterface {
Q_OBJECT Q_OBJECT
protected: protected:
QMap<int, Server_Room *> rooms; QMap<int, Server_Room *> rooms;
bool deleted; bool deleted;
Server_DatabaseInterface *databaseInterface; Server_DatabaseInterface *databaseInterface;
AuthenticationResult authState; AuthenticationResult authState;
bool acceptsUserListChanges; bool acceptsUserListChanges;
bool acceptsRoomListChanges; bool acceptsRoomListChanges;
virtual void logDebugMessage(const QString &message) { } virtual void logDebugMessage(const QString & /* message */) { }
private: private:
QList<int> messageSizeOverTime, messageCountOverTime; QList<int> messageSizeOverTime, messageCountOverTime;
int timeRunning, lastDataReceived; int timeRunning, lastDataReceived;
QTimer *pingClock; QTimer *pingClock;
virtual void transmitProtocolItem(const ServerMessage &item) = 0; virtual void transmitProtocolItem(const ServerMessage &item) = 0;
Response::ResponseCode cmdPing(const Command_Ping &cmd, ResponseContainer &rc); Response::ResponseCode cmdPing(const Command_Ping &cmd, ResponseContainer &rc);
Response::ResponseCode cmdLogin(const Command_Login &cmd, ResponseContainer &rc); Response::ResponseCode cmdLogin(const Command_Login &cmd, ResponseContainer &rc);
Response::ResponseCode cmdMessage(const Command_Message &cmd, ResponseContainer &rc); Response::ResponseCode cmdMessage(const Command_Message &cmd, ResponseContainer &rc);
Response::ResponseCode cmdGetGamesOfUser(const Command_GetGamesOfUser &cmd, ResponseContainer &rc); Response::ResponseCode cmdGetGamesOfUser(const Command_GetGamesOfUser &cmd, ResponseContainer &rc);
Response::ResponseCode cmdGetUserInfo(const Command_GetUserInfo &cmd, ResponseContainer &rc); Response::ResponseCode cmdGetUserInfo(const Command_GetUserInfo &cmd, ResponseContainer &rc);
Response::ResponseCode cmdListRooms(const Command_ListRooms &cmd, ResponseContainer &rc); Response::ResponseCode cmdListRooms(const Command_ListRooms &cmd, ResponseContainer &rc);
Response::ResponseCode cmdJoinRoom(const Command_JoinRoom &cmd, ResponseContainer &rc); Response::ResponseCode cmdJoinRoom(const Command_JoinRoom &cmd, ResponseContainer &rc);
Response::ResponseCode cmdListUsers(const Command_ListUsers &cmd, ResponseContainer &rc); Response::ResponseCode cmdListUsers(const Command_ListUsers &cmd, ResponseContainer &rc);
Response::ResponseCode cmdLeaveRoom(const Command_LeaveRoom &cmd, Server_Room *room, ResponseContainer &rc); Response::ResponseCode cmdLeaveRoom(const Command_LeaveRoom &cmd, Server_Room *room, ResponseContainer &rc);
Response::ResponseCode cmdRoomSay(const Command_RoomSay &cmd, Server_Room *room, ResponseContainer &rc); Response::ResponseCode cmdRoomSay(const Command_RoomSay &cmd, Server_Room *room, ResponseContainer &rc);
Response::ResponseCode cmdCreateGame(const Command_CreateGame &cmd, Server_Room *room, ResponseContainer &rc); Response::ResponseCode cmdCreateGame(const Command_CreateGame &cmd, Server_Room *room, ResponseContainer &rc);
Response::ResponseCode cmdJoinGame(const Command_JoinGame &cmd, Server_Room *room, ResponseContainer &rc); Response::ResponseCode cmdJoinGame(const Command_JoinGame &cmd, Server_Room *room, ResponseContainer &rc);
Response::ResponseCode processSessionCommandContainer(const CommandContainer &cont, ResponseContainer &rc); Response::ResponseCode processSessionCommandContainer(const CommandContainer &cont, ResponseContainer &rc);
virtual Response::ResponseCode processExtendedSessionCommand(int cmdType, const SessionCommand &cmd, ResponseContainer &rc) { return Response::RespFunctionNotAllowed; } virtual Response::ResponseCode processExtendedSessionCommand(int /* cmdType */, const SessionCommand & /* cmd */, ResponseContainer & /* rc */) { return Response::RespFunctionNotAllowed; }
Response::ResponseCode processRoomCommandContainer(const CommandContainer &cont, ResponseContainer &rc); Response::ResponseCode processRoomCommandContainer(const CommandContainer &cont, ResponseContainer &rc);
Response::ResponseCode processGameCommandContainer(const CommandContainer &cont, ResponseContainer &rc); Response::ResponseCode processGameCommandContainer(const CommandContainer &cont, ResponseContainer &rc);
Response::ResponseCode processModeratorCommandContainer(const CommandContainer &cont, ResponseContainer &rc); Response::ResponseCode processModeratorCommandContainer(const CommandContainer &cont, ResponseContainer &rc);
virtual Response::ResponseCode processExtendedModeratorCommand(int cmdType, const ModeratorCommand &cmd, ResponseContainer &rc) { return Response::RespFunctionNotAllowed; } virtual Response::ResponseCode processExtendedModeratorCommand(int /* cmdType */, const ModeratorCommand & /* cmd */, ResponseContainer & /* rc */) { return Response::RespFunctionNotAllowed; }
Response::ResponseCode processAdminCommandContainer(const CommandContainer &cont, ResponseContainer &rc); Response::ResponseCode processAdminCommandContainer(const CommandContainer &cont, ResponseContainer &rc);
virtual Response::ResponseCode processExtendedAdminCommand(int cmdType, const AdminCommand &cmd, ResponseContainer &rc) { return Response::RespFunctionNotAllowed; } virtual Response::ResponseCode processExtendedAdminCommand(int /* cmdType */, const AdminCommand & /* cmd */, ResponseContainer & /* rc */) { return Response::RespFunctionNotAllowed; }
private slots: private slots:
void pingClockTimeout(); void pingClockTimeout();
public slots: public slots:
void prepareDestroy(); void prepareDestroy();
public: public:
Server_ProtocolHandler(Server *_server, Server_DatabaseInterface *_databaseInterface, QObject *parent = 0); Server_ProtocolHandler(Server *_server, Server_DatabaseInterface *_databaseInterface, QObject *parent = 0);
~Server_ProtocolHandler(); ~Server_ProtocolHandler();
bool getAcceptsUserListChanges() const { return acceptsUserListChanges; } bool getAcceptsUserListChanges() const { return acceptsUserListChanges; }
bool getAcceptsRoomListChanges() const { return acceptsRoomListChanges; } bool getAcceptsRoomListChanges() const { return acceptsRoomListChanges; }
virtual QString getAddress() const = 0; virtual QString getAddress() const = 0;
Server_DatabaseInterface *getDatabaseInterface() const { return databaseInterface; } Server_DatabaseInterface *getDatabaseInterface() const { return databaseInterface; }
int getLastCommandTime() const { return timeRunning - lastDataReceived; } int getLastCommandTime() const { return timeRunning - lastDataReceived; }
void processCommandContainer(const CommandContainer &cont); void processCommandContainer(const CommandContainer &cont);
void sendProtocolItem(const Response &item); void sendProtocolItem(const Response &item);
void sendProtocolItem(const SessionEvent &item); void sendProtocolItem(const SessionEvent &item);
void sendProtocolItem(const GameEventContainer &item); void sendProtocolItem(const GameEventContainer &item);
void sendProtocolItem(const RoomEvent &item); void sendProtocolItem(const RoomEvent &item);
}; };
#endif #endif

View file

@ -4,20 +4,20 @@
void Server_RemoteUserInterface::sendProtocolItem(const Response &item) void Server_RemoteUserInterface::sendProtocolItem(const Response &item)
{ {
server->sendIsl_Response(item, userInfo->server_id(), userInfo->session_id()); server->sendIsl_Response(item, userInfo->server_id(), userInfo->session_id());
} }
void Server_RemoteUserInterface::sendProtocolItem(const SessionEvent &item) void Server_RemoteUserInterface::sendProtocolItem(const SessionEvent &item)
{ {
server->sendIsl_SessionEvent(item, userInfo->server_id(), userInfo->session_id()); server->sendIsl_SessionEvent(item, userInfo->server_id(), userInfo->session_id());
} }
void Server_RemoteUserInterface::sendProtocolItem(const GameEventContainer &item) void Server_RemoteUserInterface::sendProtocolItem(const GameEventContainer &item)
{ {
server->sendIsl_GameEventContainer(item, userInfo->server_id(), userInfo->session_id()); server->sendIsl_GameEventContainer(item, userInfo->server_id(), userInfo->session_id());
} }
void Server_RemoteUserInterface::sendProtocolItem(const RoomEvent &item) void Server_RemoteUserInterface::sendProtocolItem(const RoomEvent &item)
{ {
server->sendIsl_RoomEvent(item, userInfo->server_id(), userInfo->session_id()); server->sendIsl_RoomEvent(item, userInfo->server_id(), userInfo->session_id());
} }

View file

@ -5,14 +5,14 @@
class Server_RemoteUserInterface : public Server_AbstractUserInterface { class Server_RemoteUserInterface : public Server_AbstractUserInterface {
public: public:
Server_RemoteUserInterface(Server *_server, const ServerInfo_User_Container &_userInfoContainer) : Server_AbstractUserInterface(_server, _userInfoContainer) { } Server_RemoteUserInterface(Server *_server, const ServerInfo_User_Container &_userInfoContainer) : Server_AbstractUserInterface(_server, _userInfoContainer) { }
int getLastCommandTime() const { return 0; } int getLastCommandTime() const { return 0; }
void sendProtocolItem(const Response &item); void sendProtocolItem(const Response &item);
void sendProtocolItem(const SessionEvent &item); void sendProtocolItem(const SessionEvent &item);
void sendProtocolItem(const GameEventContainer &item); void sendProtocolItem(const GameEventContainer &item);
void sendProtocolItem(const RoomEvent &item); void sendProtocolItem(const RoomEvent &item);
}; };
#endif #endif

View file

@ -3,64 +3,64 @@
#include "server_game.h" #include "server_game.h"
GameEventStorageItem::GameEventStorageItem(const ::google::protobuf::Message &_event, int _playerId, EventRecipients _recipients) GameEventStorageItem::GameEventStorageItem(const ::google::protobuf::Message &_event, int _playerId, EventRecipients _recipients)
: event(new GameEvent), recipients(_recipients) : event(new GameEvent), recipients(_recipients)
{ {
event->GetReflection()->MutableMessage(event, _event.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(_event); event->GetReflection()->MutableMessage(event, _event.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(_event);
event->set_player_id(_playerId); event->set_player_id(_playerId);
} }
GameEventStorageItem::~GameEventStorageItem() GameEventStorageItem::~GameEventStorageItem()
{ {
delete event; delete event;
} }
GameEventStorage::GameEventStorage() GameEventStorage::GameEventStorage()
: gameEventContext(0) : gameEventContext(0)
{ {
} }
GameEventStorage::~GameEventStorage() GameEventStorage::~GameEventStorage()
{ {
delete gameEventContext; delete gameEventContext;
for (int i = 0; i < gameEventList.size(); ++i) for (int i = 0; i < gameEventList.size(); ++i)
delete gameEventList[i]; delete gameEventList[i];
} }
void GameEventStorage::setGameEventContext(const ::google::protobuf::Message &_gameEventContext) void GameEventStorage::setGameEventContext(const ::google::protobuf::Message &_gameEventContext)
{ {
delete gameEventContext; delete gameEventContext;
gameEventContext = new GameEventContext; gameEventContext = new GameEventContext;
gameEventContext->GetReflection()->MutableMessage(gameEventContext, _gameEventContext.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(_gameEventContext); gameEventContext->GetReflection()->MutableMessage(gameEventContext, _gameEventContext.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(_gameEventContext);
} }
void GameEventStorage::enqueueGameEvent(const ::google::protobuf::Message &event, int playerId, GameEventStorageItem::EventRecipients recipients, int _privatePlayerId) void GameEventStorage::enqueueGameEvent(const ::google::protobuf::Message &event, int playerId, GameEventStorageItem::EventRecipients recipients, int _privatePlayerId)
{ {
gameEventList.append(new GameEventStorageItem(event, playerId, recipients)); gameEventList.append(new GameEventStorageItem(event, playerId, recipients));
if (_privatePlayerId != -1) if (_privatePlayerId != -1)
privatePlayerId = _privatePlayerId; privatePlayerId = _privatePlayerId;
} }
void GameEventStorage::sendToGame(Server_Game *game) void GameEventStorage::sendToGame(Server_Game *game)
{ {
if (gameEventList.isEmpty()) if (gameEventList.isEmpty())
return; return;
GameEventContainer *contPrivate = new GameEventContainer; GameEventContainer *contPrivate = new GameEventContainer;
GameEventContainer *contOthers = new GameEventContainer; GameEventContainer *contOthers = new GameEventContainer;
for (int i = 0; i < gameEventList.size(); ++i) { for (int i = 0; i < gameEventList.size(); ++i) {
const GameEvent &event = gameEventList[i]->getGameEvent(); const GameEvent &event = gameEventList[i]->getGameEvent();
const GameEventStorageItem::EventRecipients recipients = gameEventList[i]->getRecipients(); const GameEventStorageItem::EventRecipients recipients = gameEventList[i]->getRecipients();
if (recipients.testFlag(GameEventStorageItem::SendToPrivate)) if (recipients.testFlag(GameEventStorageItem::SendToPrivate))
contPrivate->add_event_list()->CopyFrom(event); contPrivate->add_event_list()->CopyFrom(event);
if (recipients.testFlag(GameEventStorageItem::SendToOthers)) if (recipients.testFlag(GameEventStorageItem::SendToOthers))
contOthers->add_event_list()->CopyFrom(event); contOthers->add_event_list()->CopyFrom(event);
} }
if (gameEventContext) { if (gameEventContext) {
contPrivate->mutable_context()->CopyFrom(*gameEventContext); contPrivate->mutable_context()->CopyFrom(*gameEventContext);
contOthers->mutable_context()->CopyFrom(*gameEventContext); contOthers->mutable_context()->CopyFrom(*gameEventContext);
} }
game->sendGameEventContainer(contPrivate, GameEventStorageItem::SendToPrivate, privatePlayerId); game->sendGameEventContainer(contPrivate, GameEventStorageItem::SendToPrivate, privatePlayerId);
game->sendGameEventContainer(contOthers, GameEventStorageItem::SendToOthers, privatePlayerId); game->sendGameEventContainer(contOthers, GameEventStorageItem::SendToOthers, privatePlayerId);
} }
ResponseContainer::ResponseContainer(int _cmdId) ResponseContainer::ResponseContainer(int _cmdId)
@ -70,9 +70,9 @@ ResponseContainer::ResponseContainer(int _cmdId)
ResponseContainer::~ResponseContainer() ResponseContainer::~ResponseContainer()
{ {
delete responseExtension; delete responseExtension;
for (int i = 0; i < preResponseQueue.size(); ++i) for (int i = 0; i < preResponseQueue.size(); ++i)
delete preResponseQueue[i].second; delete preResponseQueue[i].second;
for (int i = 0; i < postResponseQueue.size(); ++i) for (int i = 0; i < postResponseQueue.size(); ++i)
delete postResponseQueue[i].second; delete postResponseQueue[i].second;
} }

View file

@ -10,54 +10,54 @@ class Server_Game;
class GameEventStorageItem { class GameEventStorageItem {
public: public:
enum EventRecipient { SendToPrivate = 0x01, SendToOthers = 0x02}; enum EventRecipient { SendToPrivate = 0x01, SendToOthers = 0x02};
Q_DECLARE_FLAGS(EventRecipients, EventRecipient) Q_DECLARE_FLAGS(EventRecipients, EventRecipient)
private: private:
GameEvent *event; GameEvent *event;
EventRecipients recipients; EventRecipients recipients;
public: public:
GameEventStorageItem(const ::google::protobuf::Message &_event, int _playerId, EventRecipients _recipients); GameEventStorageItem(const ::google::protobuf::Message &_event, int _playerId, EventRecipients _recipients);
~GameEventStorageItem(); ~GameEventStorageItem();
const GameEvent &getGameEvent() const { return *event; } const GameEvent &getGameEvent() const { return *event; }
EventRecipients getRecipients() const { return recipients; } EventRecipients getRecipients() const { return recipients; }
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS(GameEventStorageItem::EventRecipients) Q_DECLARE_OPERATORS_FOR_FLAGS(GameEventStorageItem::EventRecipients)
class GameEventStorage { class GameEventStorage {
private: private:
::google::protobuf::Message *gameEventContext; ::google::protobuf::Message *gameEventContext;
QList<GameEventStorageItem *> gameEventList; QList<GameEventStorageItem *> gameEventList;
int privatePlayerId; int privatePlayerId;
public: public:
GameEventStorage(); GameEventStorage();
~GameEventStorage(); ~GameEventStorage();
void setGameEventContext(const ::google::protobuf::Message &_gameEventContext); void setGameEventContext(const ::google::protobuf::Message &_gameEventContext);
::google::protobuf::Message *getGameEventContext() const { return gameEventContext; } ::google::protobuf::Message *getGameEventContext() const { return gameEventContext; }
const QList<GameEventStorageItem *> &getGameEventList() const { return gameEventList; } const QList<GameEventStorageItem *> &getGameEventList() const { return gameEventList; }
int getPrivatePlayerId() const { return privatePlayerId; } int getPrivatePlayerId() const { return privatePlayerId; }
void enqueueGameEvent(const ::google::protobuf::Message &event, int playerId, GameEventStorageItem::EventRecipients recipients = GameEventStorageItem::SendToPrivate | GameEventStorageItem::SendToOthers, int _privatePlayerId = -1); void enqueueGameEvent(const ::google::protobuf::Message &event, int playerId, GameEventStorageItem::EventRecipients recipients = GameEventStorageItem::SendToPrivate | GameEventStorageItem::SendToOthers, int _privatePlayerId = -1);
void sendToGame(Server_Game *game); void sendToGame(Server_Game *game);
}; };
class ResponseContainer { class ResponseContainer {
private: private:
int cmdId; int cmdId;
::google::protobuf::Message *responseExtension; ::google::protobuf::Message *responseExtension;
QList<QPair<ServerMessage::MessageType, ::google::protobuf::Message *> > preResponseQueue, postResponseQueue; QList<QPair<ServerMessage::MessageType, ::google::protobuf::Message *> > preResponseQueue, postResponseQueue;
public: public:
ResponseContainer(int _cmdId); ResponseContainer(int _cmdId);
~ResponseContainer(); ~ResponseContainer();
int getCmdId() const { return cmdId; } int getCmdId() const { return cmdId; }
void setResponseExtension(::google::protobuf::Message *_responseExtension) { responseExtension = _responseExtension; } void setResponseExtension(::google::protobuf::Message *_responseExtension) { responseExtension = _responseExtension; }
::google::protobuf::Message *getResponseExtension() const { return responseExtension; } ::google::protobuf::Message *getResponseExtension() const { return responseExtension; }
void enqueuePreResponseItem(ServerMessage::MessageType type, ::google::protobuf::Message *item) { preResponseQueue.append(qMakePair(type, item)); } void enqueuePreResponseItem(ServerMessage::MessageType type, ::google::protobuf::Message *item) { preResponseQueue.append(qMakePair(type, item)); }
void enqueuePostResponseItem(ServerMessage::MessageType type, ::google::protobuf::Message *item) { postResponseQueue.append(qMakePair(type, item)); } void enqueuePostResponseItem(ServerMessage::MessageType type, ::google::protobuf::Message *item) { postResponseQueue.append(qMakePair(type, item)); }
const QList<QPair<ServerMessage::MessageType, ::google::protobuf::Message *> > &getPreResponseQueue() const { return preResponseQueue; } const QList<QPair<ServerMessage::MessageType, ::google::protobuf::Message *> > &getPreResponseQueue() const { return preResponseQueue; }
const QList<QPair<ServerMessage::MessageType, ::google::protobuf::Message *> > &getPostResponseQueue() const { return postResponseQueue; } const QList<QPair<ServerMessage::MessageType, ::google::protobuf::Message *> > &getPostResponseQueue() const { return postResponseQueue; }
}; };
#endif #endif

View file

@ -13,326 +13,326 @@
#include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.h>
Server_Room::Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, const QStringList &_gameTypes, Server *parent) Server_Room::Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, const QStringList &_gameTypes, Server *parent)
: QObject(parent), id(_id), name(_name), description(_description), autoJoin(_autoJoin), joinMessage(_joinMessage), gameTypes(_gameTypes), gamesLock(QReadWriteLock::Recursive) : QObject(parent), id(_id), name(_name), description(_description), autoJoin(_autoJoin), joinMessage(_joinMessage), gameTypes(_gameTypes), gamesLock(QReadWriteLock::Recursive)
{ {
connect(this, SIGNAL(gameListChanged(ServerInfo_Game)), this, SLOT(broadcastGameListUpdate(ServerInfo_Game)), Qt::QueuedConnection); connect(this, SIGNAL(gameListChanged(ServerInfo_Game)), this, SLOT(broadcastGameListUpdate(ServerInfo_Game)), Qt::QueuedConnection);
} }
Server_Room::~Server_Room() Server_Room::~Server_Room()
{ {
qDebug("Server_Room destructor"); qDebug("Server_Room destructor");
gamesLock.lockForWrite(); gamesLock.lockForWrite();
const QList<Server_Game *> gameList = games.values(); const QList<Server_Game *> gameList = games.values();
for (int i = 0; i < gameList.size(); ++i) for (int i = 0; i < gameList.size(); ++i)
delete gameList[i]; delete gameList[i];
games.clear(); games.clear();
gamesLock.unlock(); gamesLock.unlock();
usersLock.lockForWrite(); usersLock.lockForWrite();
users.clear(); users.clear();
usersLock.unlock(); usersLock.unlock();
} }
Server *Server_Room::getServer() const Server *Server_Room::getServer() const
{ {
return static_cast<Server *>(parent()); return static_cast<Server *>(parent());
} }
const ServerInfo_Room &Server_Room::getInfo(ServerInfo_Room &result, bool complete, bool showGameTypes, bool includeExternalData) const const ServerInfo_Room &Server_Room::getInfo(ServerInfo_Room &result, bool complete, bool showGameTypes, bool includeExternalData) const
{ {
result.set_room_id(id); result.set_room_id(id);
result.set_name(name.toStdString()); result.set_name(name.toStdString());
result.set_description(description.toStdString()); result.set_description(description.toStdString());
result.set_auto_join(autoJoin); result.set_auto_join(autoJoin);
gamesLock.lockForRead(); gamesLock.lockForRead();
result.set_game_count(games.size() + externalGames.size()); result.set_game_count(games.size() + externalGames.size());
if (complete) { if (complete) {
QMapIterator<int, Server_Game *> gameIterator(games); QMapIterator<int, Server_Game *> gameIterator(games);
while (gameIterator.hasNext()) while (gameIterator.hasNext())
gameIterator.next().value()->getInfo(*result.add_game_list()); gameIterator.next().value()->getInfo(*result.add_game_list());
if (includeExternalData) { if (includeExternalData) {
QMapIterator<int, ServerInfo_Game> externalGameIterator(externalGames); QMapIterator<int, ServerInfo_Game> externalGameIterator(externalGames);
while (externalGameIterator.hasNext()) while (externalGameIterator.hasNext())
result.add_game_list()->CopyFrom(externalGameIterator.next().value()); result.add_game_list()->CopyFrom(externalGameIterator.next().value());
} }
} }
gamesLock.unlock(); gamesLock.unlock();
usersLock.lockForRead(); usersLock.lockForRead();
result.set_player_count(users.size() + externalUsers.size()); result.set_player_count(users.size() + externalUsers.size());
if (complete) { if (complete) {
QMapIterator<QString, Server_ProtocolHandler *> userIterator(users); QMapIterator<QString, Server_ProtocolHandler *> userIterator(users);
while (userIterator.hasNext()) while (userIterator.hasNext())
result.add_user_list()->CopyFrom(userIterator.next().value()->copyUserInfo(false)); result.add_user_list()->CopyFrom(userIterator.next().value()->copyUserInfo(false));
if (includeExternalData) { if (includeExternalData) {
QMapIterator<QString, ServerInfo_User_Container> externalUserIterator(externalUsers); QMapIterator<QString, ServerInfo_User_Container> externalUserIterator(externalUsers);
while (externalUserIterator.hasNext()) while (externalUserIterator.hasNext())
result.add_user_list()->CopyFrom(externalUserIterator.next().value().copyUserInfo(false)); result.add_user_list()->CopyFrom(externalUserIterator.next().value().copyUserInfo(false));
} }
} }
usersLock.unlock(); usersLock.unlock();
if (complete || showGameTypes) if (complete || showGameTypes)
for (int i = 0; i < gameTypes.size(); ++i) { for (int i = 0; i < gameTypes.size(); ++i) {
ServerInfo_GameType *gameTypeInfo = result.add_gametype_list(); ServerInfo_GameType *gameTypeInfo = result.add_gametype_list();
gameTypeInfo->set_game_type_id(i); gameTypeInfo->set_game_type_id(i);
gameTypeInfo->set_description(gameTypes[i].toStdString()); gameTypeInfo->set_description(gameTypes[i].toStdString());
} }
return result; return result;
} }
RoomEvent *Server_Room::prepareRoomEvent(const ::google::protobuf::Message &roomEvent) RoomEvent *Server_Room::prepareRoomEvent(const ::google::protobuf::Message &roomEvent)
{ {
RoomEvent *event = new RoomEvent; RoomEvent *event = new RoomEvent;
event->set_room_id(id); event->set_room_id(id);
event->GetReflection()->MutableMessage(event, roomEvent.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(roomEvent); event->GetReflection()->MutableMessage(event, roomEvent.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(roomEvent);
return event; return event;
} }
void Server_Room::addClient(Server_ProtocolHandler *client) void Server_Room::addClient(Server_ProtocolHandler *client)
{ {
Event_JoinRoom event; Event_JoinRoom event;
event.mutable_user_info()->CopyFrom(client->copyUserInfo(false)); event.mutable_user_info()->CopyFrom(client->copyUserInfo(false));
sendRoomEvent(prepareRoomEvent(event)); sendRoomEvent(prepareRoomEvent(event));
ServerInfo_Room roomInfo; ServerInfo_Room roomInfo;
roomInfo.set_room_id(id); roomInfo.set_room_id(id);
usersLock.lockForWrite(); usersLock.lockForWrite();
users.insert(QString::fromStdString(client->getUserInfo()->name()), client); users.insert(QString::fromStdString(client->getUserInfo()->name()), client);
roomInfo.set_player_count(users.size() + externalUsers.size()); roomInfo.set_player_count(users.size() + externalUsers.size());
usersLock.unlock(); usersLock.unlock();
// XXX This can be removed during the next client update. // XXX This can be removed during the next client update.
gamesLock.lockForRead(); gamesLock.lockForRead();
roomInfo.set_game_count(games.size() + externalGames.size()); roomInfo.set_game_count(games.size() + externalGames.size());
gamesLock.unlock(); gamesLock.unlock();
// ----------- // -----------
emit roomInfoChanged(roomInfo); emit roomInfoChanged(roomInfo);
} }
void Server_Room::removeClient(Server_ProtocolHandler *client) void Server_Room::removeClient(Server_ProtocolHandler *client)
{ {
usersLock.lockForWrite(); usersLock.lockForWrite();
users.remove(QString::fromStdString(client->getUserInfo()->name())); users.remove(QString::fromStdString(client->getUserInfo()->name()));
ServerInfo_Room roomInfo; ServerInfo_Room roomInfo;
roomInfo.set_room_id(id); roomInfo.set_room_id(id);
roomInfo.set_player_count(users.size() + externalUsers.size()); roomInfo.set_player_count(users.size() + externalUsers.size());
usersLock.unlock(); usersLock.unlock();
Event_LeaveRoom event; Event_LeaveRoom event;
event.set_name(client->getUserInfo()->name()); event.set_name(client->getUserInfo()->name());
sendRoomEvent(prepareRoomEvent(event)); sendRoomEvent(prepareRoomEvent(event));
// XXX This can be removed during the next client update. // XXX This can be removed during the next client update.
gamesLock.lockForRead(); gamesLock.lockForRead();
roomInfo.set_game_count(games.size() + externalGames.size()); roomInfo.set_game_count(games.size() + externalGames.size());
gamesLock.unlock(); gamesLock.unlock();
// ----------- // -----------
emit roomInfoChanged(roomInfo); emit roomInfoChanged(roomInfo);
} }
void Server_Room::addExternalUser(const ServerInfo_User &userInfo) void Server_Room::addExternalUser(const ServerInfo_User &userInfo)
{ {
// This function is always called from the Server thread with server->roomsMutex locked. // This function is always called from the Server thread with server->roomsMutex locked.
ServerInfo_User_Container userInfoContainer(userInfo); ServerInfo_User_Container userInfoContainer(userInfo);
Event_JoinRoom event; Event_JoinRoom event;
event.mutable_user_info()->CopyFrom(userInfoContainer.copyUserInfo(false)); event.mutable_user_info()->CopyFrom(userInfoContainer.copyUserInfo(false));
sendRoomEvent(prepareRoomEvent(event), false); sendRoomEvent(prepareRoomEvent(event), false);
ServerInfo_Room roomInfo; ServerInfo_Room roomInfo;
roomInfo.set_room_id(id); roomInfo.set_room_id(id);
usersLock.lockForWrite(); usersLock.lockForWrite();
externalUsers.insert(QString::fromStdString(userInfo.name()), userInfoContainer); externalUsers.insert(QString::fromStdString(userInfo.name()), userInfoContainer);
roomInfo.set_player_count(users.size() + externalUsers.size()); roomInfo.set_player_count(users.size() + externalUsers.size());
usersLock.unlock(); usersLock.unlock();
emit roomInfoChanged(roomInfo); emit roomInfoChanged(roomInfo);
} }
void Server_Room::removeExternalUser(const QString &name) void Server_Room::removeExternalUser(const QString &name)
{ {
// This function is always called from the Server thread with server->roomsMutex locked. // This function is always called from the Server thread with server->roomsMutex locked.
ServerInfo_Room roomInfo; ServerInfo_Room roomInfo;
roomInfo.set_room_id(id); roomInfo.set_room_id(id);
usersLock.lockForWrite(); usersLock.lockForWrite();
if (externalUsers.contains(name)) if (externalUsers.contains(name))
externalUsers.remove(name); externalUsers.remove(name);
roomInfo.set_player_count(users.size() + externalUsers.size()); roomInfo.set_player_count(users.size() + externalUsers.size());
usersLock.unlock(); usersLock.unlock();
Event_LeaveRoom event; Event_LeaveRoom event;
event.set_name(name.toStdString()); event.set_name(name.toStdString());
sendRoomEvent(prepareRoomEvent(event), false); sendRoomEvent(prepareRoomEvent(event), false);
emit roomInfoChanged(roomInfo); emit roomInfoChanged(roomInfo);
} }
void Server_Room::updateExternalGameList(const ServerInfo_Game &gameInfo) void Server_Room::updateExternalGameList(const ServerInfo_Game &gameInfo)
{ {
// This function is always called from the Server thread with server->roomsMutex locked. // This function is always called from the Server thread with server->roomsMutex locked.
ServerInfo_Room roomInfo; ServerInfo_Room roomInfo;
roomInfo.set_room_id(id); roomInfo.set_room_id(id);
gamesLock.lockForWrite(); gamesLock.lockForWrite();
if (!gameInfo.has_player_count() && externalGames.contains(gameInfo.game_id())) if (!gameInfo.has_player_count() && externalGames.contains(gameInfo.game_id()))
externalGames.remove(gameInfo.game_id()); externalGames.remove(gameInfo.game_id());
else else
externalGames.insert(gameInfo.game_id(), gameInfo); externalGames.insert(gameInfo.game_id(), gameInfo);
roomInfo.set_game_count(games.size() + externalGames.size()); roomInfo.set_game_count(games.size() + externalGames.size());
gamesLock.unlock(); gamesLock.unlock();
broadcastGameListUpdate(gameInfo, false); broadcastGameListUpdate(gameInfo, false);
emit roomInfoChanged(roomInfo); emit roomInfoChanged(roomInfo);
} }
Response::ResponseCode Server_Room::processJoinGameCommand(const Command_JoinGame &cmd, ResponseContainer &rc, Server_AbstractUserInterface *userInterface) Response::ResponseCode Server_Room::processJoinGameCommand(const Command_JoinGame &cmd, ResponseContainer &rc, Server_AbstractUserInterface *userInterface)
{ {
// This function is called from the Server thread and from the S_PH thread. // This function is called from the Server thread and from the S_PH thread.
// server->roomsMutex is always locked. // server->roomsMutex is always locked.
QReadLocker roomGamesLocker(&gamesLock); QReadLocker roomGamesLocker(&gamesLock);
Server_Game *g = games.value(cmd.game_id()); Server_Game *g = games.value(cmd.game_id());
if (!g) { if (!g) {
if (externalGames.contains(cmd.game_id())) { if (externalGames.contains(cmd.game_id())) {
CommandContainer cont; CommandContainer cont;
cont.set_cmd_id(rc.getCmdId()); cont.set_cmd_id(rc.getCmdId());
RoomCommand *roomCommand = cont.add_room_command(); RoomCommand *roomCommand = cont.add_room_command();
roomCommand->GetReflection()->MutableMessage(roomCommand, cmd.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(cmd); roomCommand->GetReflection()->MutableMessage(roomCommand, cmd.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(cmd);
getServer()->sendIsl_RoomCommand(cont, externalGames.value(cmd.game_id()).server_id(), userInterface->getUserInfo()->session_id(), id); getServer()->sendIsl_RoomCommand(cont, externalGames.value(cmd.game_id()).server_id(), userInterface->getUserInfo()->session_id(), id);
return Response::RespNothing; return Response::RespNothing;
} else } else
return Response::RespNameNotFound; return Response::RespNameNotFound;
} }
QMutexLocker gameLocker(&g->gameMutex); QMutexLocker gameLocker(&g->gameMutex);
Response::ResponseCode result = g->checkJoin(userInterface->getUserInfo(), QString::fromStdString(cmd.password()), cmd.spectator(), cmd.override_restrictions()); Response::ResponseCode result = g->checkJoin(userInterface->getUserInfo(), QString::fromStdString(cmd.password()), cmd.spectator(), cmd.override_restrictions());
if (result == Response::RespOk) if (result == Response::RespOk)
g->addPlayer(userInterface, rc, cmd.spectator()); g->addPlayer(userInterface, rc, cmd.spectator());
return result; return result;
} }
void Server_Room::say(const QString &userName, const QString &s, bool sendToIsl) void Server_Room::say(const QString &userName, const QString &s, bool sendToIsl)
{ {
Event_RoomSay event; Event_RoomSay event;
event.set_name(userName.toStdString()); event.set_name(userName.toStdString());
event.set_message(s.toStdString()); event.set_message(s.toStdString());
sendRoomEvent(prepareRoomEvent(event), sendToIsl); sendRoomEvent(prepareRoomEvent(event), sendToIsl);
} }
void Server_Room::sendRoomEvent(RoomEvent *event, bool sendToIsl) void Server_Room::sendRoomEvent(RoomEvent *event, bool sendToIsl)
{ {
usersLock.lockForRead(); usersLock.lockForRead();
{ {
QMapIterator<QString, Server_ProtocolHandler *> userIterator(users); QMapIterator<QString, Server_ProtocolHandler *> userIterator(users);
while (userIterator.hasNext()) while (userIterator.hasNext())
userIterator.next().value()->sendProtocolItem(*event); userIterator.next().value()->sendProtocolItem(*event);
} }
usersLock.unlock(); usersLock.unlock();
if (sendToIsl) if (sendToIsl)
static_cast<Server *>(parent())->sendIsl_RoomEvent(*event); static_cast<Server *>(parent())->sendIsl_RoomEvent(*event);
delete event; delete event;
} }
void Server_Room::broadcastGameListUpdate(const ServerInfo_Game &gameInfo, bool sendToIsl) void Server_Room::broadcastGameListUpdate(const ServerInfo_Game &gameInfo, bool sendToIsl)
{ {
Event_ListGames event; Event_ListGames event;
event.add_game_list()->CopyFrom(gameInfo); event.add_game_list()->CopyFrom(gameInfo);
sendRoomEvent(prepareRoomEvent(event), sendToIsl); sendRoomEvent(prepareRoomEvent(event), sendToIsl);
} }
void Server_Room::addGame(Server_Game *game) void Server_Room::addGame(Server_Game *game)
{ {
ServerInfo_Room roomInfo; ServerInfo_Room roomInfo;
roomInfo.set_room_id(id); roomInfo.set_room_id(id);
gamesLock.lockForWrite(); gamesLock.lockForWrite();
connect(game, SIGNAL(gameInfoChanged(ServerInfo_Game)), this, SLOT(broadcastGameListUpdate(ServerInfo_Game))); connect(game, SIGNAL(gameInfoChanged(ServerInfo_Game)), this, SLOT(broadcastGameListUpdate(ServerInfo_Game)));
game->gameMutex.lock(); game->gameMutex.lock();
games.insert(game->getGameId(), game); games.insert(game->getGameId(), game);
ServerInfo_Game gameInfo; ServerInfo_Game gameInfo;
game->getInfo(gameInfo); game->getInfo(gameInfo);
roomInfo.set_game_count(games.size() + externalGames.size()); roomInfo.set_game_count(games.size() + externalGames.size());
game->gameMutex.unlock(); game->gameMutex.unlock();
gamesLock.unlock(); gamesLock.unlock();
// XXX This can be removed during the next client update. // XXX This can be removed during the next client update.
usersLock.lockForRead(); usersLock.lockForRead();
roomInfo.set_player_count(users.size() + externalUsers.size()); roomInfo.set_player_count(users.size() + externalUsers.size());
usersLock.unlock(); usersLock.unlock();
// ----------- // -----------
emit gameListChanged(gameInfo); emit gameListChanged(gameInfo);
emit roomInfoChanged(roomInfo); emit roomInfoChanged(roomInfo);
} }
void Server_Room::removeGame(Server_Game *game) void Server_Room::removeGame(Server_Game *game)
{ {
// No need to lock gamesLock or gameMutex. This method is only // No need to lock gamesLock or gameMutex. This method is only
// called from ~Server_Game, which locks both mutexes anyway beforehand. // called from ~Server_Game, which locks both mutexes anyway beforehand.
disconnect(game, 0, this, 0); disconnect(game, 0, this, 0);
ServerInfo_Game gameInfo; ServerInfo_Game gameInfo;
game->getInfo(gameInfo); game->getInfo(gameInfo);
emit gameListChanged(gameInfo); emit gameListChanged(gameInfo);
games.remove(game->getGameId()); games.remove(game->getGameId());
ServerInfo_Room roomInfo; ServerInfo_Room roomInfo;
roomInfo.set_room_id(id); roomInfo.set_room_id(id);
roomInfo.set_game_count(games.size() + externalGames.size()); roomInfo.set_game_count(games.size() + externalGames.size());
// XXX This can be removed during the next client update. // XXX This can be removed during the next client update.
usersLock.lockForRead(); usersLock.lockForRead();
roomInfo.set_player_count(users.size() + externalUsers.size()); roomInfo.set_player_count(users.size() + externalUsers.size());
usersLock.unlock(); usersLock.unlock();
// ----------- // -----------
emit roomInfoChanged(roomInfo); emit roomInfoChanged(roomInfo);
} }
int Server_Room::getGamesCreatedByUser(const QString &userName) const int Server_Room::getGamesCreatedByUser(const QString &userName) const
{ {
QReadLocker locker(&gamesLock); QReadLocker locker(&gamesLock);
QMapIterator<int, Server_Game *> gamesIterator(games); QMapIterator<int, Server_Game *> gamesIterator(games);
int result = 0; int result = 0;
while (gamesIterator.hasNext()) while (gamesIterator.hasNext())
if (gamesIterator.next().value()->getCreatorInfo()->name() == userName.toStdString()) if (gamesIterator.next().value()->getCreatorInfo()->name() == userName.toStdString())
++result; ++result;
return result; return result;
} }
QList<ServerInfo_Game> Server_Room::getGamesOfUser(const QString &userName) const QList<ServerInfo_Game> Server_Room::getGamesOfUser(const QString &userName) const
{ {
QReadLocker locker(&gamesLock); QReadLocker locker(&gamesLock);
QList<ServerInfo_Game> result; QList<ServerInfo_Game> result;
QMapIterator<int, Server_Game *> gamesIterator(games); QMapIterator<int, Server_Game *> gamesIterator(games);
while (gamesIterator.hasNext()) { while (gamesIterator.hasNext()) {
Server_Game *game = gamesIterator.next().value(); Server_Game *game = gamesIterator.next().value();
if (game->containsUser(userName)) { if (game->containsUser(userName)) {
ServerInfo_Game gameInfo; ServerInfo_Game gameInfo;
game->getInfo(gameInfo); game->getInfo(gameInfo);
result.append(gameInfo); result.append(gameInfo);
} }
} }
return result; return result;
} }

View file

@ -24,58 +24,58 @@ class ResponseContainer;
class Server_AbstractUserInterface; class Server_AbstractUserInterface;
class Server_Room : public QObject { class Server_Room : public QObject {
Q_OBJECT Q_OBJECT
signals: signals:
void roomInfoChanged(const ServerInfo_Room &roomInfo); void roomInfoChanged(const ServerInfo_Room &roomInfo);
void gameListChanged(const ServerInfo_Game &gameInfo); void gameListChanged(const ServerInfo_Game &gameInfo);
private: private:
int id; int id;
QString name; QString name;
QString description; QString description;
bool autoJoin; bool autoJoin;
QString joinMessage; QString joinMessage;
QStringList gameTypes; QStringList gameTypes;
QMap<int, Server_Game *> games; QMap<int, Server_Game *> games;
QMap<int, ServerInfo_Game> externalGames; QMap<int, ServerInfo_Game> externalGames;
QMap<QString, Server_ProtocolHandler *> users; QMap<QString, Server_ProtocolHandler *> users;
QMap<QString, ServerInfo_User_Container> externalUsers; QMap<QString, ServerInfo_User_Container> externalUsers;
private slots: private slots:
void broadcastGameListUpdate(const ServerInfo_Game &gameInfo, bool sendToIsl = true); void broadcastGameListUpdate(const ServerInfo_Game &gameInfo, bool sendToIsl = true);
public: public:
mutable QReadWriteLock usersLock; mutable QReadWriteLock usersLock;
mutable QReadWriteLock gamesLock; mutable QReadWriteLock gamesLock;
Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, const QStringList &_gameTypes, Server *parent); Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, const QStringList &_gameTypes, Server *parent);
~Server_Room(); ~Server_Room();
int getId() const { return id; } int getId() const { return id; }
QString getName() const { return name; } QString getName() const { return name; }
QString getDescription() const { return description; } QString getDescription() const { return description; }
bool getAutoJoin() const { return autoJoin; } bool getAutoJoin() const { return autoJoin; }
QString getJoinMessage() const { return joinMessage; } QString getJoinMessage() const { return joinMessage; }
const QStringList &getGameTypes() const { return gameTypes; } const QStringList &getGameTypes() const { return gameTypes; }
const QMap<int, Server_Game *> &getGames() const { return games; } const QMap<int, Server_Game *> &getGames() const { return games; }
const QMap<int, ServerInfo_Game> &getExternalGames() const { return externalGames; } const QMap<int, ServerInfo_Game> &getExternalGames() const { return externalGames; }
Server *getServer() const; Server *getServer() const;
const ServerInfo_Room &getInfo(ServerInfo_Room &result, bool complete, bool showGameTypes = false, bool includeExternalData = true) const; const ServerInfo_Room &getInfo(ServerInfo_Room &result, bool complete, bool showGameTypes = false, bool includeExternalData = true) const;
int getGamesCreatedByUser(const QString &name) const; int getGamesCreatedByUser(const QString &name) const;
QList<ServerInfo_Game> getGamesOfUser(const QString &name) const; QList<ServerInfo_Game> getGamesOfUser(const QString &name) const;
void addClient(Server_ProtocolHandler *client); void addClient(Server_ProtocolHandler *client);
void removeClient(Server_ProtocolHandler *client); void removeClient(Server_ProtocolHandler *client);
void addExternalUser(const ServerInfo_User &userInfo); void addExternalUser(const ServerInfo_User &userInfo);
void removeExternalUser(const QString &name); void removeExternalUser(const QString &name);
const QMap<QString, ServerInfo_User_Container> &getExternalUsers() const { return externalUsers; } const QMap<QString, ServerInfo_User_Container> &getExternalUsers() const { return externalUsers; }
void updateExternalGameList(const ServerInfo_Game &gameInfo); void updateExternalGameList(const ServerInfo_Game &gameInfo);
Response::ResponseCode processJoinGameCommand(const Command_JoinGame &cmd, ResponseContainer &rc, Server_AbstractUserInterface *userInterface); Response::ResponseCode processJoinGameCommand(const Command_JoinGame &cmd, ResponseContainer &rc, Server_AbstractUserInterface *userInterface);
void say(const QString &userName, const QString &s, bool sendToIsl = true); void say(const QString &userName, const QString &s, bool sendToIsl = true);
void addGame(Server_Game *game); void addGame(Server_Game *game);
void removeGame(Server_Game *game); void removeGame(Server_Game *game);
void sendRoomEvent(RoomEvent *event, bool sendToIsl = true); void sendRoomEvent(RoomEvent *event, bool sendToIsl = true);
RoomEvent *prepareRoomEvent(const ::google::protobuf::Message &roomEvent); RoomEvent *prepareRoomEvent(const ::google::protobuf::Message &roomEvent);
}; };
#endif #endif

View file

@ -7,46 +7,46 @@ ServerInfo_User_Container::ServerInfo_User_Container(ServerInfo_User *_userInfo)
} }
ServerInfo_User_Container::ServerInfo_User_Container(const ServerInfo_User &_userInfo) ServerInfo_User_Container::ServerInfo_User_Container(const ServerInfo_User &_userInfo)
: userInfo(new ServerInfo_User(_userInfo)) : userInfo(new ServerInfo_User(_userInfo))
{ {
} }
ServerInfo_User_Container::ServerInfo_User_Container(const ServerInfo_User_Container &other) ServerInfo_User_Container::ServerInfo_User_Container(const ServerInfo_User_Container &other)
{ {
if (other.userInfo) if (other.userInfo)
userInfo = new ServerInfo_User(*other.userInfo); userInfo = new ServerInfo_User(*other.userInfo);
else else
userInfo = 0; userInfo = 0;
} }
ServerInfo_User_Container::~ServerInfo_User_Container() ServerInfo_User_Container::~ServerInfo_User_Container()
{ {
delete userInfo; delete userInfo;
} }
void ServerInfo_User_Container::setUserInfo(const ServerInfo_User &_userInfo) void ServerInfo_User_Container::setUserInfo(const ServerInfo_User &_userInfo)
{ {
userInfo = new ServerInfo_User(_userInfo); userInfo = new ServerInfo_User(_userInfo);
} }
ServerInfo_User &ServerInfo_User_Container::copyUserInfo(ServerInfo_User &result, bool complete, bool internalInfo, bool sessionInfo) const ServerInfo_User &ServerInfo_User_Container::copyUserInfo(ServerInfo_User &result, bool complete, bool internalInfo, bool sessionInfo) const
{ {
if (userInfo) { if (userInfo) {
result.CopyFrom(*userInfo); result.CopyFrom(*userInfo);
if (!sessionInfo) { if (!sessionInfo) {
result.clear_session_id(); result.clear_session_id();
result.clear_address(); result.clear_address();
} }
if (!internalInfo) if (!internalInfo)
result.clear_id(); result.clear_id();
if (!complete) if (!complete)
result.clear_avatar_bmp(); result.clear_avatar_bmp();
} }
return result; return result;
} }
ServerInfo_User ServerInfo_User_Container::copyUserInfo(bool complete, bool internalInfo, bool sessionInfo) const ServerInfo_User ServerInfo_User_Container::copyUserInfo(bool complete, bool internalInfo, bool sessionInfo) const
{ {
ServerInfo_User result; ServerInfo_User result;
return copyUserInfo(result, complete, internalInfo, sessionInfo); return copyUserInfo(result, complete, internalInfo, sessionInfo);
} }

View file

@ -5,16 +5,16 @@ class ServerInfo_User;
class ServerInfo_User_Container { class ServerInfo_User_Container {
protected: protected:
ServerInfo_User *userInfo; ServerInfo_User *userInfo;
public: public:
ServerInfo_User_Container(ServerInfo_User *_userInfo = 0); ServerInfo_User_Container(ServerInfo_User *_userInfo = 0);
ServerInfo_User_Container(const ServerInfo_User &_userInfo); ServerInfo_User_Container(const ServerInfo_User &_userInfo);
ServerInfo_User_Container(const ServerInfo_User_Container &other); ServerInfo_User_Container(const ServerInfo_User_Container &other);
virtual ~ServerInfo_User_Container(); virtual ~ServerInfo_User_Container();
ServerInfo_User *getUserInfo() const { return userInfo; } ServerInfo_User *getUserInfo() const { return userInfo; }
void setUserInfo(const ServerInfo_User &_userInfo); void setUserInfo(const ServerInfo_User &_userInfo);
ServerInfo_User &copyUserInfo(ServerInfo_User &result, bool complete, bool internalInfo = false, bool sessionInfo = false) const; ServerInfo_User &copyUserInfo(ServerInfo_User &result, bool complete, bool internalInfo = false, bool sessionInfo = false) const;
ServerInfo_User copyUserInfo(bool complete, bool internalInfo = false, bool sessionInfo = false) const; ServerInfo_User copyUserInfo(bool complete, bool internalInfo = false, bool sessionInfo = false) const;
}; };
#endif #endif

56
doc/cards.xsd Normal file
View file

@ -0,0 +1,56 @@
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="cockatrice_carddatabase">
<xs:complexType>
<xs:sequence>
<xs:element name="sets">
<xs:complexType>
<xs:sequence>
<xs:element name="set" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="name"/>
<xs:element type="xs:string" name="longname"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="cards">
<xs:complexType>
<xs:sequence>
<xs:element name="card" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="name"/>
<xs:element name="set" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:int" name="muId" use="optional"/>
<xs:attribute type="xs:anyURI" name="picUrl" use="optional"/>
<xs:attribute type="xs:anyURI" name="picUrlHq" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element type="xs:string" name="color" minOccurs="0" maxOccurs="unbounded"/>
<xs:element type="xs:string" name="manacost"/>
<xs:element type="xs:string" name="type"/>
<xs:element type="xs:string" name="pt" minOccurs="0"/>
<xs:element type="xs:integer" name="tablerow"/>
<xs:element type="xs:string" name="text"/>
<xs:element type="xs:boolean" name="cipt" minOccurs="0"/>
<xs:element type="xs:integer" name="loyalty" minOccurs="0"/>
<xs:element type="xs:boolean" name="token" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:integer" name="version"/>
</xs:complexType>
</xs:element>
</xs:schema>

View file

@ -16,6 +16,19 @@ SET(oracle_SOURCES
../cockatrice/src/qt-json/json.cpp ../cockatrice/src/qt-json/json.cpp
) )
set(oracle_RESOURCES oracle.qrc)
if(WIN32)
set(oracle_SOURCES ${oracle_SOURCES} oracle.rc)
endif(WIN32)
if(APPLE)
set(MACOSX_BUNDLE_ICON_FILE appicon.icns)
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
set(oracle_SOURCES ${oracle_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns)
ENDIF(APPLE)
set(ORACLE_LIBS) set(ORACLE_LIBS)
# Qt4 stuff # Qt4 stuff
@ -29,6 +42,10 @@ if(Qt4_FOUND)
include_directories(${QT_INCLUDES}) include_directories(${QT_INCLUDES})
LIST(APPEND ORACLE_LIBS ${QT_QTMAIN_LIBRARY}) LIST(APPEND ORACLE_LIBS ${QT_QTMAIN_LIBRARY})
LIST(APPEND ORACLE_LIBS ${QT_LIBRARIES}) LIST(APPEND ORACLE_LIBS ${QT_LIBRARIES})
# Let cmake chew Qt4's translations and resource files
# Note: header files are MOC-ed automatically by cmake
QT4_ADD_RESOURCES(oracle_RESOURCES_RCC ${oracle_RESOURCES})
endif() endif()
# qt5 stuff # qt5 stuff
@ -64,6 +81,10 @@ if(Qt5Widgets_FOUND)
list(APPEND ORACLE_LIBS Svg) list(APPEND ORACLE_LIBS Svg)
endif() endif()
# Let cmake chew Qt5's translations and resource files
# Note: header files are MOC-ed automatically by cmake
QT5_ADD_RESOURCES(oracle_RESOURCES_RCC ${oracle_RESOURCES})
# guess plugins and libraries directory # guess plugins and libraries directory
set(QT_PLUGINS_DIR "${Qt5Widgets_DIR}/../../../plugins") set(QT_PLUGINS_DIR "${Qt5Widgets_DIR}/../../../plugins")
get_target_property(QT_LIBRARY_DIR Qt5::Core LOCATION) get_target_property(QT_LIBRARY_DIR Qt5::Core LOCATION)
@ -73,7 +94,7 @@ endif()
INCLUDE_DIRECTORIES(../cockatrice/src) INCLUDE_DIRECTORIES(../cockatrice/src)
# Build oracle binary and link it # Build oracle binary and link it
ADD_EXECUTABLE(oracle WIN32 MACOSX_BUNDLE ${oracle_SOURCES} ${oracle_MOC_SRCS}) ADD_EXECUTABLE(oracle WIN32 MACOSX_BUNDLE ${oracle_SOURCES} ${oracle_RESOURCES_RCC} ${oracle_MOC_SRCS})
if(Qt4_FOUND) if(Qt4_FOUND)
if(MSVC) if(MSVC)
@ -94,6 +115,8 @@ if(UNIX)
else() else()
# Assume linux # Assume linux
INSTALL(TARGETS oracle RUNTIME DESTINATION bin/) INSTALL(TARGETS oracle RUNTIME DESTINATION bin/)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/oracle.png DESTINATION ${ICONDIR}/hicolor/48x48/apps)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/oracle.svg DESTINATION ${ICONDIR}/hicolor/scalable/apps)
endif() endif()
elseif(WIN32) elseif(WIN32)
INSTALL(TARGETS oracle RUNTIME DESTINATION ./) INSTALL(TARGETS oracle RUNTIME DESTINATION ./)

View file

@ -4,5 +4,5 @@ Version=1.0
Type=Application Type=Application
Name=Cockatrice Oracle downloader Name=Cockatrice Oracle downloader
Exec=oracle Exec=oracle
Icon=cockatrice Icon=oracle
Categories=Game;CardGame; Categories=Game;CardGame;

5
oracle/oracle.qrc Normal file
View file

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/" >
<file alias="resources/appicon.svg">resources/oracle.svg</file>
</qresource>
</RCC>

1
oracle/oracle.rc Normal file
View file

@ -0,0 +1 @@
ID1_ICON1 ICON DISCARDABLE "resources/appicon.ico"

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

BIN
oracle/resources/oracle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

228
oracle/resources/oracle.svg Normal file
View file

@ -0,0 +1,228 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="300.0036"
height="300"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.48.2 r9819"
sodipodi:docname="back.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.0"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs4">
<linearGradient
id="linearGradient3169">
<stop
style="stop-color:#0000ff;stop-opacity:1;"
offset="0"
id="stop3171" />
<stop
style="stop-color:#000067;stop-opacity:1;"
offset="1"
id="stop3173" />
</linearGradient>
<linearGradient
id="linearGradient4766">
<stop
style="stop-color:#784421;stop-opacity:1;"
offset="0"
id="stop4768" />
<stop
style="stop-color:#3d2210;stop-opacity:0;"
offset="1"
id="stop4770" />
</linearGradient>
<linearGradient
id="linearGradient4758">
<stop
style="stop-color:#a05a2c;stop-opacity:1;"
offset="0"
id="stop4760" />
<stop
style="stop-color:#3d2210;stop-opacity:1;"
offset="1"
id="stop4762" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" />
<inkscape:perspective
id="perspective2484"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 526.18109 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4758"
id="linearGradient4764"
x1="466.09601"
y1="485.96021"
x2="715.14801"
y2="485.96021"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4766"
id="linearGradient4772"
x1="496.548"
y1="485.26816"
x2="683.31201"
y2="485.26816"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4766"
id="linearGradient2396"
gradientUnits="userSpaceOnUse"
x1="661.24402"
y1="602.90814"
x2="431.5"
y2="201.5482"
gradientTransform="matrix(0.9650128,0,0,0.9948433,-449.70565,-312.80927)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4758"
id="linearGradient2399"
gradientUnits="userSpaceOnUse"
x1="590.62201"
y1="434.7522"
x2="698.54004"
y2="517.79218"
gradientTransform="matrix(0.9650128,0,0,0.9948433,-449.70565,-312.80927)" />
<filter
inkscape:collect="always"
id="filter3287"
color-interpolation-filters="sRGB">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.88403668"
id="feGaussianBlur3289" />
</filter>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4766"
id="linearGradient3057"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.84875138,0,0,0.874988,-395.5345,-274.89225)"
x1="661.24402"
y1="602.90814"
x2="431.5"
y2="201.5482" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4758"
id="linearGradient3059"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.84875138,0,0,0.874988,-395.5345,-274.89225)"
x1="590.62201"
y1="434.7522"
x2="698.54004"
y2="517.79218" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4911765"
inkscape:cx="164.24505"
inkscape:cy="113.77996"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1280"
inkscape:window-height="725"
inkscape:window-x="0"
inkscape:window-y="25"
fit-margin-left="44.18"
fit-margin-right="44.18"
fit-margin-top="0"
fit-margin-bottom="0"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(44.245053,-0.31708717)">
<rect
style="fill:url(#linearGradient3059);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:17.23539734;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect2490"
width="194.4082"
height="282.76462"
x="8.5526457"
y="8.9347858"
inkscape:export-xdpi="969.46002"
inkscape:export-ydpi="969.46002" />
<rect
style="fill:url(#linearGradient3057);fill-opacity:1;stroke:#000000;stroke-width:1.72353971;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect3302"
width="156.81871"
height="244.01315"
x="26.760056"
y="27.704998" />
<path
sodipodi:type="arc"
style="opacity:0.39208954;fill:#a05a2c;stroke:#000000;stroke-width:2.00029755;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter3287)"
id="path3304"
sodipodi:cx="589.58398"
sodipodi:cy="489.76617"
sodipodi:rx="71.968002"
sodipodi:ry="128.71201"
d="m 661.55199,489.76617 c 0,71.08568 -32.22118,128.71201 -71.96801,128.71201 -39.74683,0 -71.968,-57.62633 -71.968,-128.71201 0,-71.08567 32.22117,-128.712 71.968,-128.712 39.74683,0 71.96801,57.62633 71.96801,128.712 z"
transform="matrix(1.0026379,0,0,0.89548037,-485.67617,-289.46994)" />
<flowRoot
xml:space="preserve"
id="flowRoot3021"
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><flowRegion
id="flowRegion3023"><rect
id="rect3025"
width="151.92514"
height="235.58012"
x="50.000679"
y="60.188515" /></flowRegion><flowPara
id="flowPara3027"></flowPara></flowRoot> <text
xml:space="preserve"
style="font-size:35.18093872px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Songti SC;-inkscape-font-specification:Songti SC"
x="-14.38486"
y="244.29784"
id="text3029"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3031"
x="-14.38486"
y="244.29784"
style="font-size:390.50842285px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#ffffff;font-family:STKaiti;-inkscape-font-specification:STKaiti Bold Italic">o</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.9 KiB

View file

@ -1,5 +1,6 @@
#include <QApplication> #include <QApplication>
#include <QTextCodec> #include <QTextCodec>
#include <QIcon>
#include "oraclewizard.h" #include "oraclewizard.h"
#include "settingscache.h" #include "settingscache.h"
@ -22,6 +23,10 @@ int main(int argc, char *argv[])
settingsCache = new SettingsCache; settingsCache = new SettingsCache;
OracleWizard wizard; OracleWizard wizard;
QIcon icon(":/resources/appicon.svg");
wizard.setWindowIcon(icon);
wizard.show(); wizard.show();
return app.exec(); return app.exec();

View file

@ -80,8 +80,8 @@ CardInfo *OracleImporter::addCard(const QString &setName,
cardCost.remove(QChar('}')); cardCost.remove(QChar('}'));
CardInfo *card; CardInfo *card;
if (cardHash.contains(cardName)) { if (cards.contains(cardName)) {
card = cardHash.value(cardName); card = cards.value(cardName);
if (splitCard && !card->getText().contains(fullCardText)) if (splitCard && !card->getText().contains(fullCardText))
card->setText(card->getText() + "\n---\n" + fullCardText); card->setText(card->getText() + "\n---\n" + fullCardText);
} else { } else {
@ -121,7 +121,7 @@ CardInfo *OracleImporter::addCard(const QString &setName,
tableRow = 2; tableRow = 2;
card->setTableRow(tableRow); card->setTableRow(tableRow);
cardHash.insert(cardName, card); cards.insert(cardName, card);
} }
card->setMuId(setName, cardId); card->setMuId(setName, cardId);
@ -141,6 +141,7 @@ int OracleImporter::importTextSpoiler(CardSet *set, const QVariant &data)
QString cardText; QString cardText;
int cardId; int cardId;
int cardLoyalty; int cardLoyalty;
bool cardIsToken = false;
QMap<int, QVariantMap> splitCards; QMap<int, QVariantMap> splitCards;
while (it.hasNext()) { while (it.hasNext()) {
@ -201,9 +202,15 @@ int OracleImporter::importTextSpoiler(CardSet *set, const QVariant &data)
cardText = map.contains("text") ? map.value("text").toString() : QString(""); cardText = map.contains("text") ? map.value("text").toString() : QString("");
cardId = map.contains("multiverseid") ? map.value("multiverseid").toInt() : 0; cardId = map.contains("multiverseid") ? map.value("multiverseid").toInt() : 0;
cardLoyalty = map.contains("loyalty") ? map.value("loyalty").toInt() : 0; cardLoyalty = map.contains("loyalty") ? map.value("loyalty").toInt() : 0;
cardIsToken = map.value("layout") == "token";
// Distinguish Vanguard cards from regular cards of the same name.
if (map.value("layout") == "vanguard") {
cardName += " Avatar";
}
} }
CardInfo *card = addCard(set->getShortName(), cardName, false, cardId, cardCost, cardType, cardPT, cardLoyalty, cardText.split("\n")); CardInfo *card = addCard(set->getShortName(), cardName, cardIsToken, cardId, cardCost, cardType, cardPT, cardLoyalty, cardText.split("\n"));
if (!set->contains(card)) { if (!set->contains(card)) {
card->addToSet(set); card->addToSet(set);
@ -229,8 +236,8 @@ int OracleImporter::startImport()
continue; continue;
CardSet *set = new CardSet(curSet->getShortName(), curSet->getLongName()); CardSet *set = new CardSet(curSet->getShortName(), curSet->getLongName());
if (!setHash.contains(set->getShortName())) if (!sets.contains(set->getShortName()))
setHash.insert(set->getShortName(), set); sets.insert(set->getShortName(), set);
int setCards = importTextSpoiler(set, curSet->getCards()); int setCards = importTextSpoiler(set, curSet->getCards());

View file

@ -383,7 +383,7 @@ void SaveSetsPage::initializePage()
QMessageBox::critical(this, tr("Error"), tr("No set has been imported.")); QMessageBox::critical(this, tr("Error"), tr("No set has been imported."));
} }
void SaveSetsPage::updateTotalProgress(int cardsImported, int setIndex, const QString &setName) void SaveSetsPage::updateTotalProgress(int cardsImported, int /* setIndex */, const QString &setName)
{ {
if (setName.isEmpty()) { if (setName.isEmpty()) {
messageLog->append("<b>" + tr("Import finished: %1 cards.").arg(wizard()->importer->getCardList().size()) + "</b>"); messageLog->append("<b>" + tr("Import finished: %1 cards.").arg(wizard()->importer->getCardList().size()) + "</b>");
@ -418,9 +418,12 @@ bool SaveSetsPage::validatePage()
return false; return false;
} }
if (wizard()->importer->saveToFile(fileName)) if (wizard()->importer->saveToFile(fileName))
{
ok = true; ok = true;
else QMessageBox::information(this, tr("Success"), tr("The card database has been saved successfully."));
} else {
QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to the desired location.")); QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to the desired location."));
}
} while (!ok); } while (!ok);
return true; return true;

View file

@ -0,0 +1,3 @@
#!/bin/bash
# SCHEDULE WITH CRONTAB BASED ON TIME PERIOD REPLAYS SHOULD BE SAVED UNTIL (EX: SCHEDULE ONCE A WEEK TO KEEP A WEEKS WORTH OF REPLAYS IN THE DB)
mysql --defaults-file=./mysql.cnf -h localhost -e 'truncate table servatrice.cockatrice_replays;truncate table servatrice.cockatrice_replays_access'

View file

@ -0,0 +1,3 @@
#!/bin/bash
# SCHEDULE WITH CRONTAB TO RUN ONCE A MONTH
mysql --defaults-file=./mysql.cnf -h localhost -e "delete from servatrice.cockatrice_sessions where start_time < DATE_SUB(now(), INTERVAL 1 MONTH)"

View file

@ -0,0 +1,3 @@
[client]
user={db_username}
password={db_password}

View file

@ -29,6 +29,7 @@
#include "server_logger.h" #include "server_logger.h"
#include "rng_sfmt.h" #include "rng_sfmt.h"
#include "version_string.h" #include "version_string.h"
#include <google/protobuf/stubs/common.h>
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
#include <signal.h> #include <signal.h>
#endif #endif
@ -37,6 +38,23 @@ RNG_Abstract *rng;
ServerLogger *logger; ServerLogger *logger;
QThread *loggerThread; QThread *loggerThread;
/* Prototypes */
void testRNG();
void testHash();
#if QT_VERSION < 0x050000
void myMessageOutput(QtMsgType type, const char *msg);
void myMessageOutput2(QtMsgType type, const char *msg);
#else
void myMessageOutput(QtMsgType type, const QMessageLogContext &, const QString &msg);
void myMessageOutput2(QtMsgType type, const QMessageLogContext &, const QString &msg);
#endif
#ifdef Q_OS_UNIX
void sigSegvHandler(int sig);
#endif
/* Implementations */
void testRNG() void testRNG()
{ {
const int n = 500000; const int n = 500000;
@ -216,5 +234,8 @@ int main(int argc, char *argv[])
loggerThread->wait(); loggerThread->wait();
delete loggerThread; delete loggerThread;
// Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();
return retval; return retval;
} }

View file

@ -18,12 +18,15 @@ QString PasswordHasher::computeHash(const QString &password, const QString &salt
QByteArray passwordBuffer = (salt + password).toUtf8(); QByteArray passwordBuffer = (salt + password).toUtf8();
int hashLen = gcry_md_get_algo_dlen(algo); int hashLen = gcry_md_get_algo_dlen(algo);
char hash[hashLen], tmp[hashLen]; char *hash = new char[hashLen], *tmp = new char[hashLen];
gcry_md_hash_buffer(algo, hash, passwordBuffer.data(), passwordBuffer.size()); gcry_md_hash_buffer(algo, hash, passwordBuffer.data(), passwordBuffer.size());
for (int i = 1; i < rounds; ++i) { for (int i = 1; i < rounds; ++i) {
memcpy(tmp, hash, hashLen); memcpy(tmp, hash, hashLen);
gcry_md_hash_buffer(algo, hash, tmp, hashLen); gcry_md_hash_buffer(algo, hash, tmp, hashLen);
} }
return salt + QString(QByteArray(hash, hashLen).toBase64()); QString hashedPass = salt + QString(QByteArray(hash, hashLen).toBase64());
delete[] tmp;
delete[] hash;
return hashedPass;
} }

View file

@ -78,7 +78,11 @@ Servatrice_GameServer::~Servatrice_GameServer()
} }
} }
#if QT_VERSION < 0x050000
void Servatrice_GameServer::incomingConnection(int socketDescriptor) void Servatrice_GameServer::incomingConnection(int socketDescriptor)
#else
void Servatrice_GameServer::incomingConnection(qintptr socketDescriptor)
#endif
{ {
// Determine connection pool with smallest client count // Determine connection pool with smallest client count
int minClientCount = -1; int minClientCount = -1;

Some files were not shown because too many files have changed in this diff Show more