interface & client tab for replay transfer
This commit is contained in:
parent
faf6b2c5cb
commit
c6c6a970c6
36 changed files with 702 additions and 52 deletions
|
@ -54,6 +54,7 @@ SET(cockatrice_SOURCES
|
||||||
src/tab_message.cpp
|
src/tab_message.cpp
|
||||||
src/tab_game.cpp
|
src/tab_game.cpp
|
||||||
src/tab_deck_storage.cpp
|
src/tab_deck_storage.cpp
|
||||||
|
src/tab_replays.cpp
|
||||||
src/tab_supervisor.cpp
|
src/tab_supervisor.cpp
|
||||||
src/tab_admin.cpp
|
src/tab_admin.cpp
|
||||||
src/tab_userlists.cpp
|
src/tab_userlists.cpp
|
||||||
|
@ -61,6 +62,7 @@ SET(cockatrice_SOURCES
|
||||||
src/userlist.cpp
|
src/userlist.cpp
|
||||||
src/userinfobox.cpp
|
src/userinfobox.cpp
|
||||||
src/remotedecklist_treewidget.cpp
|
src/remotedecklist_treewidget.cpp
|
||||||
|
src/remotereplaylist_treewidget.cpp
|
||||||
src/deckview.cpp
|
src/deckview.cpp
|
||||||
src/playerlistwidget.cpp
|
src/playerlistwidget.cpp
|
||||||
src/pixmapgenerator.cpp
|
src/pixmapgenerator.cpp
|
||||||
|
@ -122,6 +124,7 @@ SET(cockatrice_HEADERS
|
||||||
src/tab_message.h
|
src/tab_message.h
|
||||||
src/tab_game.h
|
src/tab_game.h
|
||||||
src/tab_deck_storage.h
|
src/tab_deck_storage.h
|
||||||
|
src/tab_replays.h
|
||||||
src/tab_supervisor.h
|
src/tab_supervisor.h
|
||||||
src/tab_admin.h
|
src/tab_admin.h
|
||||||
src/tab_userlists.h
|
src/tab_userlists.h
|
||||||
|
@ -129,6 +132,7 @@ SET(cockatrice_HEADERS
|
||||||
src/userlist.h
|
src/userlist.h
|
||||||
src/userinfobox.h
|
src/userinfobox.h
|
||||||
src/remotedecklist_treewidget.h
|
src/remotedecklist_treewidget.h
|
||||||
|
src/remotereplaylist_treewidget.h
|
||||||
src/deckview.h
|
src/deckview.h
|
||||||
src/playerlistwidget.h
|
src/playerlistwidget.h
|
||||||
src/settingscache.h
|
src/settingscache.h
|
||||||
|
|
|
@ -20,9 +20,9 @@ LocalServerInterface *LocalServer::newConnection()
|
||||||
return lsi;
|
return lsi;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerInfo_User LocalServer::getUserData(const QString &name)
|
ServerInfo_User LocalServer::getUserData(const QString &name, bool /*withId*/)
|
||||||
{
|
{
|
||||||
ServerInfo_User result;
|
ServerInfo_User result;
|
||||||
result.set_name(name.toStdString());
|
result.set_name(name.toStdString());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ public:
|
||||||
|
|
||||||
LocalServerInterface *newConnection();
|
LocalServerInterface *newConnection();
|
||||||
protected:
|
protected:
|
||||||
ServerInfo_User getUserData(const QString &name);
|
ServerInfo_User getUserData(const QString &name, bool withId = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -18,6 +18,8 @@ private:
|
||||||
Response::ResponseCode cmdDeckDel(const Command_DeckDel & /*cmd*/, ResponseContainer & /*rc*/) { return Response::RespFunctionNotAllowed; }
|
Response::ResponseCode cmdDeckDel(const Command_DeckDel & /*cmd*/, ResponseContainer & /*rc*/) { return Response::RespFunctionNotAllowed; }
|
||||||
Response::ResponseCode cmdDeckUpload(const Command_DeckUpload & /*cmd*/, ResponseContainer & /*rc*/) { return Response::RespFunctionNotAllowed; }
|
Response::ResponseCode cmdDeckUpload(const Command_DeckUpload & /*cmd*/, ResponseContainer & /*rc*/) { return Response::RespFunctionNotAllowed; }
|
||||||
Response::ResponseCode cmdDeckDownload(const Command_DeckDownload & /*cmd*/, ResponseContainer & /*rc*/) { return Response::RespFunctionNotAllowed; }
|
Response::ResponseCode cmdDeckDownload(const Command_DeckDownload & /*cmd*/, ResponseContainer & /*rc*/) { return Response::RespFunctionNotAllowed; }
|
||||||
|
Response::ResponseCode cmdReplayList(const Command_ReplayList & /*cmd*/, ResponseContainer & /*rc*/) { return Response::RespFunctionNotAllowed; }
|
||||||
|
Response::ResponseCode cmdReplayDownload(const Command_ReplayDownload & /*cmd*/, ResponseContainer & /*rc*/) { return Response::RespFunctionNotAllowed; }
|
||||||
Response::ResponseCode cmdBanFromServer(const Command_BanFromServer & /*cmd*/, ResponseContainer & /*rc*/) { return Response::RespFunctionNotAllowed; }
|
Response::ResponseCode cmdBanFromServer(const Command_BanFromServer & /*cmd*/, ResponseContainer & /*rc*/) { return Response::RespFunctionNotAllowed; }
|
||||||
Response::ResponseCode cmdShutdownServer(const Command_ShutdownServer & /*cmd*/, ResponseContainer & /*rc*/) { return Response::RespFunctionNotAllowed; }
|
Response::ResponseCode cmdShutdownServer(const Command_ShutdownServer & /*cmd*/, ResponseContainer & /*rc*/) { return Response::RespFunctionNotAllowed; }
|
||||||
Response::ResponseCode cmdUpdateServerMessage(const Command_UpdateServerMessage & /*cmd*/, ResponseContainer & /*rc*/) { return Response::RespFunctionNotAllowed; }
|
Response::ResponseCode cmdUpdateServerMessage(const Command_UpdateServerMessage & /*cmd*/, ResponseContainer & /*rc*/) { return Response::RespFunctionNotAllowed; }
|
||||||
|
|
|
@ -51,7 +51,7 @@ PlayerTarget::PlayerTarget(Player *_owner, QGraphicsItem *parentItem)
|
||||||
{
|
{
|
||||||
setCacheMode(DeviceCoordinateCache);
|
setCacheMode(DeviceCoordinateCache);
|
||||||
|
|
||||||
const std::string bmp = _owner->getUserInfo()->avatar_bmp();
|
const std::string &bmp = _owner->getUserInfo()->avatar_bmp();
|
||||||
if (!fullPixmap.loadFromData((const uchar *) bmp.data(), bmp.size()))
|
if (!fullPixmap.loadFromData((const uchar *) bmp.data(), bmp.size()))
|
||||||
fullPixmap = QPixmap();
|
fullPixmap = QPixmap();
|
||||||
}
|
}
|
||||||
|
@ -144,4 +144,4 @@ AbstractCounter *PlayerTarget::addCounter(int _counterId, const QString &_name,
|
||||||
void PlayerTarget::delCounter()
|
void PlayerTarget::delCounter()
|
||||||
{
|
{
|
||||||
playerCounter = 0;
|
playerCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "abstractclient.h"
|
#include "abstractclient.h"
|
||||||
|
|
||||||
#include "pending_command.h"
|
#include "pending_command.h"
|
||||||
#include "pb/session_commands.pb.h"
|
#include "pb/command_deck_list.pb.h"
|
||||||
#include "pb/response_deck_list.pb.h"
|
#include "pb/response_deck_list.pb.h"
|
||||||
#include "pb/serverinfo_deckstorage.pb.h"
|
#include "pb/serverinfo_deckstorage.pb.h"
|
||||||
|
|
||||||
|
|
167
cockatrice/src/remotereplaylist_treewidget.cpp
Normal file
167
cockatrice/src/remotereplaylist_treewidget.cpp
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
#include <QFileIconProvider>
|
||||||
|
#include <QHeaderView>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
#include "remotereplaylist_treewidget.h"
|
||||||
|
#include "abstractclient.h"
|
||||||
|
|
||||||
|
#include "pending_command.h"
|
||||||
|
#include "pb/command_replay_list.pb.h"
|
||||||
|
#include "pb/response_replay_list.pb.h"
|
||||||
|
#include "pb/serverinfo_replay.pb.h"
|
||||||
|
|
||||||
|
RemoteReplayList_TreeModel::RemoteReplayList_TreeModel(AbstractClient *_client, QObject *parent)
|
||||||
|
: QAbstractItemModel(parent), client(_client)
|
||||||
|
{
|
||||||
|
QFileIconProvider fip;
|
||||||
|
fileIcon = fip.icon(QFileIconProvider::File);
|
||||||
|
|
||||||
|
refreshTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteReplayList_TreeModel::~RemoteReplayList_TreeModel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int RemoteReplayList_TreeModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
return parent.isValid() ? 0 : replays.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int RemoteReplayList_TreeModel::columnCount(const QModelIndex &/*parent*/) const
|
||||||
|
{
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant RemoteReplayList_TreeModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return QVariant();
|
||||||
|
if (index.column() > 5)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
ServerInfo_Replay *replayInfo = static_cast<ServerInfo_Replay *>(index.internalPointer());
|
||||||
|
switch (role) {
|
||||||
|
case Qt::TextAlignmentRole:
|
||||||
|
return index.column() == 0 ? Qt::AlignRight : Qt::AlignLeft;
|
||||||
|
case Qt::DisplayRole: {
|
||||||
|
switch (index.column()) {
|
||||||
|
case 0: return replayInfo->game_id();
|
||||||
|
case 1: return QString::fromStdString(replayInfo->game_name());
|
||||||
|
case 2: return QString::fromStdString(replayInfo->replay_name());
|
||||||
|
case 3: {
|
||||||
|
QStringList playerList;
|
||||||
|
for (int i = 0; i < replayInfo->player_names_size(); ++i)
|
||||||
|
playerList.append(QString::fromStdString(replayInfo->player_names(i)));
|
||||||
|
return playerList.join(", ");
|
||||||
|
}
|
||||||
|
case 4: return QDateTime::fromTime_t(replayInfo->time_started());
|
||||||
|
case 5: return replayInfo->length();
|
||||||
|
default: return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case Qt::DecorationRole:
|
||||||
|
return index.column() == 0 ? fileIcon : QVariant();
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant RemoteReplayList_TreeModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
if (orientation != Qt::Horizontal)
|
||||||
|
return QVariant();
|
||||||
|
switch (role) {
|
||||||
|
case Qt::TextAlignmentRole:
|
||||||
|
return section == 0 ? Qt::AlignRight : Qt::AlignLeft;
|
||||||
|
case Qt::DisplayRole: {
|
||||||
|
switch (section) {
|
||||||
|
case 0: return tr("Game ID");
|
||||||
|
case 1: return tr("Game name");
|
||||||
|
case 2: return tr("Replay name");
|
||||||
|
case 3: return tr("Players");
|
||||||
|
case 4: return tr("Time started");
|
||||||
|
case 5: return tr("Duration (sec)");
|
||||||
|
default: return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default: return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex RemoteReplayList_TreeModel::index(int row, int column, const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
if (!hasIndex(row, column, parent))
|
||||||
|
return QModelIndex();
|
||||||
|
|
||||||
|
return createIndex(row, column, (void *) &(replays[row]));
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex RemoteReplayList_TreeModel::parent(const QModelIndex &ind) const
|
||||||
|
{
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags RemoteReplayList_TreeModel::flags(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerInfo_Replay const* RemoteReplayList_TreeModel::getNode(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return &(replays[index.row()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteReplayList_TreeModel::refreshTree()
|
||||||
|
{
|
||||||
|
PendingCommand *pend = client->prepareSessionCommand(Command_ReplayList());
|
||||||
|
connect(pend, SIGNAL(finished(const Response &)), this, SLOT(replayListFinished(const Response &)));
|
||||||
|
|
||||||
|
client->sendCommand(pend);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteReplayList_TreeModel::replayListFinished(const Response &r)
|
||||||
|
{
|
||||||
|
const Response_ReplayList &resp = r.GetExtension(Response_ReplayList::ext);
|
||||||
|
|
||||||
|
beginResetModel();
|
||||||
|
replays.clear();
|
||||||
|
|
||||||
|
for (int i = 0; i < resp.replay_list_size(); ++i)
|
||||||
|
replays.append(resp.replay_list(i));
|
||||||
|
|
||||||
|
endResetModel();
|
||||||
|
emit treeRefreshed();
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteReplayList_TreeWidget::RemoteReplayList_TreeWidget(AbstractClient *_client, QWidget *parent)
|
||||||
|
: QTreeView(parent)
|
||||||
|
{
|
||||||
|
treeModel = new RemoteReplayList_TreeModel(_client, this);
|
||||||
|
proxyModel = new QSortFilterProxyModel(this);
|
||||||
|
proxyModel->setSourceModel(treeModel);
|
||||||
|
proxyModel->setDynamicSortFilter(true);
|
||||||
|
proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
setModel(proxyModel);
|
||||||
|
connect(treeModel, SIGNAL(treeRefreshed()), this, SLOT(expandAll()));
|
||||||
|
|
||||||
|
header()->setResizeMode(QHeaderView::ResizeToContents);
|
||||||
|
setUniformRowHeights(true);
|
||||||
|
setSortingEnabled(true);
|
||||||
|
proxyModel->sort(0, Qt::AscendingOrder);
|
||||||
|
header()->setSortIndicator(0, Qt::AscendingOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerInfo_Replay const *RemoteReplayList_TreeWidget::getNode(const QModelIndex &ind) const
|
||||||
|
{
|
||||||
|
return treeModel->getNode(proxyModel->mapToSource(ind));
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerInfo_Replay const *RemoteReplayList_TreeWidget::getCurrentItem() const
|
||||||
|
{
|
||||||
|
return getNode(selectionModel()->currentIndex());
|
||||||
|
}
|
49
cockatrice/src/remotereplaylist_treewidget.h
Normal file
49
cockatrice/src/remotereplaylist_treewidget.h
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#ifndef REMOTEREPLAYLIST_TREEWIDGET_H
|
||||||
|
#define REMOTEREPLAYLIST_TREEWIDGET_H
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QTreeView>
|
||||||
|
#include "pb/serverinfo_replay.pb.h"
|
||||||
|
|
||||||
|
class Response;
|
||||||
|
class AbstractClient;
|
||||||
|
class QSortFilterProxyModel;
|
||||||
|
|
||||||
|
class RemoteReplayList_TreeModel : public QAbstractItemModel {
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
AbstractClient *client;
|
||||||
|
QList<ServerInfo_Replay> replays;
|
||||||
|
|
||||||
|
QIcon fileIcon;
|
||||||
|
signals:
|
||||||
|
void treeRefreshed();
|
||||||
|
private slots:
|
||||||
|
void replayListFinished(const Response &r);
|
||||||
|
public:
|
||||||
|
RemoteReplayList_TreeModel(AbstractClient *_client, QObject *parent = 0);
|
||||||
|
~RemoteReplayList_TreeModel();
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const;
|
||||||
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
QModelIndex parent(const QModelIndex &index) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||||
|
void refreshTree();
|
||||||
|
ServerInfo_Replay const *getNode(const QModelIndex &index) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RemoteReplayList_TreeWidget : public QTreeView {
|
||||||
|
private:
|
||||||
|
RemoteReplayList_TreeModel *treeModel;
|
||||||
|
QSortFilterProxyModel *proxyModel;
|
||||||
|
ServerInfo_Replay const *getNode(const QModelIndex &ind) const;
|
||||||
|
public:
|
||||||
|
RemoteReplayList_TreeWidget(AbstractClient *_client, QWidget *parent = 0);
|
||||||
|
ServerInfo_Replay const *getCurrentItem() const;
|
||||||
|
void refreshTree();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -12,7 +12,6 @@ class QToolBar;
|
||||||
class QTreeWidget;
|
class QTreeWidget;
|
||||||
class QTreeWidgetItem;
|
class QTreeWidgetItem;
|
||||||
class QGroupBox;
|
class QGroupBox;
|
||||||
class ProtocolResponse;
|
|
||||||
class RemoteDeckList_TreeWidget;
|
class RemoteDeckList_TreeWidget;
|
||||||
|
|
||||||
class TabDeckStorage : public Tab {
|
class TabDeckStorage : public Tab {
|
||||||
|
|
|
@ -957,6 +957,14 @@ CardItem *TabGame::getCard(int playerId, const QString &zoneName, int cardId) co
|
||||||
return zone->getCard(cardId, QString());
|
return zone->getCard(cardId, QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString TabGame::getTabText() const
|
||||||
|
{
|
||||||
|
if (replay)
|
||||||
|
return tr("Replay %1: %2").arg(gameId).arg(gameDescription);
|
||||||
|
else
|
||||||
|
return tr("Game %1: %2").arg(gameId).arg(gameDescription);
|
||||||
|
}
|
||||||
|
|
||||||
Player *TabGame::getActiveLocalPlayer() const
|
Player *TabGame::getActiveLocalPlayer() const
|
||||||
{
|
{
|
||||||
Player *active = players.value(activePlayer, 0);
|
Player *active = players.value(activePlayer, 0);
|
||||||
|
|
|
@ -180,7 +180,7 @@ public:
|
||||||
CardItem *getCard(int playerId, const QString &zoneName, int cardId) const;
|
CardItem *getCard(int playerId, const QString &zoneName, int cardId) const;
|
||||||
bool isHost() const { return hostId == localPlayerId; }
|
bool isHost() const { return hostId == localPlayerId; }
|
||||||
int getGameId() const { return gameId; }
|
int getGameId() const { return gameId; }
|
||||||
QString getTabText() const { return tr("Game %1: %2").arg(gameId).arg(gameDescription); }
|
QString getTabText() const;
|
||||||
bool getSpectator() const { return spectator; }
|
bool getSpectator() const { return spectator; }
|
||||||
bool getSpectatorsCanTalk() const { return spectatorsCanTalk; }
|
bool getSpectatorsCanTalk() const { return spectatorsCanTalk; }
|
||||||
bool getSpectatorsSeeEverything() const { return spectatorsSeeEverything; }
|
bool getSpectatorsSeeEverything() const { return spectatorsSeeEverything; }
|
||||||
|
|
185
cockatrice/src/tab_replays.cpp
Normal file
185
cockatrice/src/tab_replays.cpp
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
#include <QTreeView>
|
||||||
|
#include <QFileSystemModel>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
#include <QToolBar>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QAction>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QHeaderView>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QInputDialog>
|
||||||
|
#include "tab_replays.h"
|
||||||
|
#include "remotereplaylist_treewidget.h"
|
||||||
|
#include "abstractclient.h"
|
||||||
|
#include "tab_game.h"
|
||||||
|
#include "settingscache.h"
|
||||||
|
|
||||||
|
#include "pending_command.h"
|
||||||
|
#include "pb/game_replay.pb.h"
|
||||||
|
#include "pb/response.pb.h"
|
||||||
|
#include "pb/response_replay_download.pb.h"
|
||||||
|
#include "pb/command_replay_download.pb.h"
|
||||||
|
|
||||||
|
TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client)
|
||||||
|
: Tab(_tabSupervisor), client(_client)
|
||||||
|
{
|
||||||
|
localDirModel = new QFileSystemModel(this);
|
||||||
|
localDirModel->setRootPath(settingsCache->getReplaysPath());
|
||||||
|
|
||||||
|
sortFilter = new QSortFilterProxyModel(this);
|
||||||
|
sortFilter->setSourceModel(localDirModel);
|
||||||
|
sortFilter->setDynamicSortFilter(true);
|
||||||
|
|
||||||
|
localDirView = new QTreeView;
|
||||||
|
localDirView->setModel(sortFilter);
|
||||||
|
localDirView->setColumnHidden(1, true);
|
||||||
|
localDirView->setRootIndex(sortFilter->mapFromSource(localDirModel->index(localDirModel->rootPath(), 0)));
|
||||||
|
localDirView->setSortingEnabled(true);
|
||||||
|
localDirView->header()->setResizeMode(QHeaderView::ResizeToContents);
|
||||||
|
sortFilter->sort(0, Qt::AscendingOrder);
|
||||||
|
localDirView->header()->setSortIndicator(0, Qt::AscendingOrder);
|
||||||
|
|
||||||
|
leftToolBar = new QToolBar;
|
||||||
|
leftToolBar->setOrientation(Qt::Horizontal);
|
||||||
|
leftToolBar->setIconSize(QSize(32, 32));
|
||||||
|
QHBoxLayout *leftToolBarLayout = new QHBoxLayout;
|
||||||
|
leftToolBarLayout->addStretch();
|
||||||
|
leftToolBarLayout->addWidget(leftToolBar);
|
||||||
|
leftToolBarLayout->addStretch();
|
||||||
|
|
||||||
|
QVBoxLayout *leftVbox = new QVBoxLayout;
|
||||||
|
leftVbox->addWidget(localDirView);
|
||||||
|
leftVbox->addLayout(leftToolBarLayout);
|
||||||
|
leftGroupBox = new QGroupBox;
|
||||||
|
leftGroupBox->setLayout(leftVbox);
|
||||||
|
|
||||||
|
rightToolBar = new QToolBar;
|
||||||
|
rightToolBar->setOrientation(Qt::Horizontal);
|
||||||
|
rightToolBar->setIconSize(QSize(32, 32));
|
||||||
|
QHBoxLayout *rightToolBarLayout = new QHBoxLayout;
|
||||||
|
rightToolBarLayout->addStretch();
|
||||||
|
rightToolBarLayout->addWidget(rightToolBar);
|
||||||
|
rightToolBarLayout->addStretch();
|
||||||
|
|
||||||
|
serverDirView = new RemoteReplayList_TreeWidget(client);
|
||||||
|
|
||||||
|
QVBoxLayout *rightVbox = new QVBoxLayout;
|
||||||
|
rightVbox->addWidget(serverDirView);
|
||||||
|
rightVbox->addLayout(rightToolBarLayout);
|
||||||
|
rightGroupBox = new QGroupBox;
|
||||||
|
rightGroupBox->setLayout(rightVbox);
|
||||||
|
|
||||||
|
QHBoxLayout *hbox = new QHBoxLayout;
|
||||||
|
hbox->addWidget(leftGroupBox);
|
||||||
|
hbox->addWidget(rightGroupBox);
|
||||||
|
|
||||||
|
aOpenLocalReplay = new QAction(this);
|
||||||
|
aOpenLocalReplay->setIcon(QIcon(":/resources/pencil.svg"));
|
||||||
|
connect(aOpenLocalReplay, SIGNAL(triggered()), this, SLOT(actOpenLocalReplay()));
|
||||||
|
aOpenRemoteReplay = new QAction(this);
|
||||||
|
aOpenRemoteReplay->setIcon(QIcon(":/resources/pencil.svg"));
|
||||||
|
connect(aOpenRemoteReplay, SIGNAL(triggered()), this, SLOT(actOpenRemoteReplay()));
|
||||||
|
aDownload = new QAction(this);
|
||||||
|
aDownload->setIcon(QIcon(":/resources/arrow_left_green.svg"));
|
||||||
|
connect(aDownload, SIGNAL(triggered()), this, SLOT(actDownload()));
|
||||||
|
|
||||||
|
leftToolBar->addAction(aOpenLocalReplay);
|
||||||
|
rightToolBar->addAction(aOpenRemoteReplay);
|
||||||
|
rightToolBar->addAction(aDownload);
|
||||||
|
|
||||||
|
retranslateUi();
|
||||||
|
setLayout(hbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabReplays::retranslateUi()
|
||||||
|
{
|
||||||
|
leftGroupBox->setTitle(tr("Local file system"));
|
||||||
|
rightGroupBox->setTitle(tr("Server replay storage"));
|
||||||
|
|
||||||
|
aOpenLocalReplay->setText(tr("Watch replay"));
|
||||||
|
aOpenRemoteReplay->setText(tr("Watch replay"));
|
||||||
|
aDownload->setText(tr("Download replay"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabReplays::actOpenLocalReplay()
|
||||||
|
{
|
||||||
|
QModelIndex curLeft = sortFilter->mapToSource(localDirView->selectionModel()->currentIndex());
|
||||||
|
if (localDirModel->isDir(curLeft))
|
||||||
|
return;
|
||||||
|
QString filePath = localDirModel->filePath(curLeft);
|
||||||
|
|
||||||
|
QFile f(filePath);
|
||||||
|
if (!f.open(QIODevice::ReadOnly))
|
||||||
|
return;
|
||||||
|
QByteArray data = f.readAll();
|
||||||
|
f.close();
|
||||||
|
|
||||||
|
GameReplay *replay = new GameReplay;
|
||||||
|
replay->ParseFromArray(data.data(), data.size());
|
||||||
|
|
||||||
|
emit openReplay(replay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabReplays::actOpenRemoteReplay()
|
||||||
|
{
|
||||||
|
ServerInfo_Replay const *curRight = serverDirView->getCurrentItem();
|
||||||
|
if (!curRight)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Command_ReplayDownload cmd;
|
||||||
|
cmd.set_game_id(curRight->game_id());
|
||||||
|
|
||||||
|
PendingCommand *pend = client->prepareSessionCommand(cmd);
|
||||||
|
connect(pend, SIGNAL(finished(const Response &)), this, SLOT(openRemoteReplayFinished(const Response &)));
|
||||||
|
client->sendCommand(pend);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabReplays::openRemoteReplayFinished(const Response &r)
|
||||||
|
{
|
||||||
|
const Response_ReplayDownload &resp = r.GetExtension(Response_ReplayDownload::ext);
|
||||||
|
GameReplay *replay = new GameReplay;
|
||||||
|
replay->ParseFromString(resp.replay_data());
|
||||||
|
|
||||||
|
emit openReplay(replay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabReplays::actDownload()
|
||||||
|
{
|
||||||
|
QString filePath;
|
||||||
|
QModelIndex curLeft = sortFilter->mapToSource(localDirView->selectionModel()->currentIndex());
|
||||||
|
if (!curLeft.isValid())
|
||||||
|
filePath = localDirModel->rootPath();
|
||||||
|
else {
|
||||||
|
while (!localDirModel->isDir(curLeft))
|
||||||
|
curLeft = curLeft.parent();
|
||||||
|
filePath = localDirModel->filePath(curLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerInfo_Replay const *curRight = serverDirView->getCurrentItem();
|
||||||
|
if (!curRight)
|
||||||
|
return;
|
||||||
|
filePath += QString("/game_%1.cor").arg(curRight->game_id());
|
||||||
|
|
||||||
|
Command_ReplayDownload cmd;
|
||||||
|
cmd.set_game_id(curRight->game_id());
|
||||||
|
|
||||||
|
PendingCommand *pend = client->prepareSessionCommand(cmd);
|
||||||
|
pend->setExtraData(filePath);
|
||||||
|
connect(pend, SIGNAL(finished(const Response &)), this, SLOT(downloadFinished(const Response &)));
|
||||||
|
client->sendCommand(pend);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabReplays::downloadFinished(const Response &r)
|
||||||
|
{
|
||||||
|
const Response_ReplayDownload &resp = r.GetExtension(Response_ReplayDownload::ext);
|
||||||
|
|
||||||
|
PendingCommand *pend = static_cast<PendingCommand *>(sender());
|
||||||
|
QString filePath = pend->getExtraData().toString();
|
||||||
|
|
||||||
|
const std::string &data = resp.replay_data();
|
||||||
|
QFile f(filePath);
|
||||||
|
f.open(QIODevice::WriteOnly);
|
||||||
|
f.write((const char *) data.data(), data.size());
|
||||||
|
f.close();
|
||||||
|
}
|
44
cockatrice/src/tab_replays.h
Normal file
44
cockatrice/src/tab_replays.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef TAB_REPLAYS_H
|
||||||
|
#define TAB_REPLAYS_H
|
||||||
|
|
||||||
|
#include "tab.h"
|
||||||
|
#include "pb/response.pb.h"
|
||||||
|
|
||||||
|
class AbstractClient;
|
||||||
|
class QTreeView;
|
||||||
|
class QFileSystemModel;
|
||||||
|
class QSortFilterProxyModel;
|
||||||
|
class QToolBar;
|
||||||
|
class QGroupBox;
|
||||||
|
class RemoteReplayList_TreeWidget;
|
||||||
|
class GameReplay;
|
||||||
|
|
||||||
|
class TabReplays : public Tab {
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
AbstractClient *client;
|
||||||
|
QTreeView *localDirView;
|
||||||
|
QFileSystemModel *localDirModel;
|
||||||
|
QSortFilterProxyModel *sortFilter;
|
||||||
|
QToolBar *leftToolBar, *rightToolBar;
|
||||||
|
RemoteReplayList_TreeWidget *serverDirView;
|
||||||
|
QGroupBox *leftGroupBox, *rightGroupBox;
|
||||||
|
|
||||||
|
QAction *aOpenLocalReplay, *aOpenRemoteReplay, *aDownload;
|
||||||
|
private slots:
|
||||||
|
void actOpenLocalReplay();
|
||||||
|
|
||||||
|
void actOpenRemoteReplay();
|
||||||
|
void openRemoteReplayFinished(const Response &r);
|
||||||
|
|
||||||
|
void actDownload();
|
||||||
|
void downloadFinished(const Response &r);
|
||||||
|
signals:
|
||||||
|
void openReplay(GameReplay *replay);
|
||||||
|
public:
|
||||||
|
TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client);
|
||||||
|
void retranslateUi();
|
||||||
|
QString getTabText() const { return tr("Game replays"); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -5,6 +5,7 @@
|
||||||
#include "tab_room.h"
|
#include "tab_room.h"
|
||||||
#include "tab_game.h"
|
#include "tab_game.h"
|
||||||
#include "tab_deck_storage.h"
|
#include "tab_deck_storage.h"
|
||||||
|
#include "tab_replays.h"
|
||||||
#include "tab_admin.h"
|
#include "tab_admin.h"
|
||||||
#include "tab_message.h"
|
#include "tab_message.h"
|
||||||
#include "tab_userlists.h"
|
#include "tab_userlists.h"
|
||||||
|
@ -138,8 +139,14 @@ void TabSupervisor::start(AbstractClient *_client, const ServerInfo_User &_userI
|
||||||
if (userInfo->user_level() & ServerInfo_User::IsRegistered) {
|
if (userInfo->user_level() & ServerInfo_User::IsRegistered) {
|
||||||
tabDeckStorage = new TabDeckStorage(this, client);
|
tabDeckStorage = new TabDeckStorage(this, client);
|
||||||
myAddTab(tabDeckStorage);
|
myAddTab(tabDeckStorage);
|
||||||
} else
|
|
||||||
|
tabReplays = new TabReplays(this, client);
|
||||||
|
connect(tabReplays, SIGNAL(openReplay(GameReplay *)), this, SLOT(openReplay(GameReplay *)));
|
||||||
|
myAddTab(tabReplays);
|
||||||
|
} else {
|
||||||
tabDeckStorage = 0;
|
tabDeckStorage = 0;
|
||||||
|
tabReplays = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (userInfo->user_level() & ServerInfo_User::IsModerator) {
|
if (userInfo->user_level() & ServerInfo_User::IsModerator) {
|
||||||
tabAdmin = new TabAdmin(this, client, (userInfo->user_level() & ServerInfo_User::IsAdmin));
|
tabAdmin = new TabAdmin(this, client, (userInfo->user_level() & ServerInfo_User::IsAdmin));
|
||||||
|
@ -155,6 +162,7 @@ void TabSupervisor::startLocal(const QList<AbstractClient *> &_clients)
|
||||||
{
|
{
|
||||||
tabUserLists = 0;
|
tabUserLists = 0;
|
||||||
tabDeckStorage = 0;
|
tabDeckStorage = 0;
|
||||||
|
tabReplays = 0;
|
||||||
tabAdmin = 0;
|
tabAdmin = 0;
|
||||||
userInfo = new ServerInfo_User;
|
userInfo = new ServerInfo_User;
|
||||||
localClients = _clients;
|
localClients = _clients;
|
||||||
|
@ -183,10 +191,12 @@ void TabSupervisor::stop()
|
||||||
tabUserLists->deleteLater();
|
tabUserLists->deleteLater();
|
||||||
tabServer->deleteLater();
|
tabServer->deleteLater();
|
||||||
tabDeckStorage->deleteLater();
|
tabDeckStorage->deleteLater();
|
||||||
|
tabReplays->deleteLater();
|
||||||
}
|
}
|
||||||
tabUserLists = 0;
|
tabUserLists = 0;
|
||||||
tabServer = 0;
|
tabServer = 0;
|
||||||
tabDeckStorage = 0;
|
tabDeckStorage = 0;
|
||||||
|
tabReplays = 0;
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
QMapIterator<int, TabRoom *> roomIterator(roomTabs);
|
QMapIterator<int, TabRoom *> roomIterator(roomTabs);
|
||||||
|
@ -306,6 +316,12 @@ TabMessage *TabSupervisor::addMessageTab(const QString &receiverName, bool focus
|
||||||
return tab;
|
return tab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabSupervisor::openReplay(GameReplay *replay)
|
||||||
|
{
|
||||||
|
TabGame *replayTab = new TabGame(replay);
|
||||||
|
myAddTab(replayTab);
|
||||||
|
}
|
||||||
|
|
||||||
void TabSupervisor::talkLeft(TabMessage *tab)
|
void TabSupervisor::talkLeft(TabMessage *tab)
|
||||||
{
|
{
|
||||||
emit setMenu(0);
|
emit setMenu(0);
|
||||||
|
|
|
@ -12,6 +12,7 @@ class TabServer;
|
||||||
class TabRoom;
|
class TabRoom;
|
||||||
class TabGame;
|
class TabGame;
|
||||||
class TabDeckStorage;
|
class TabDeckStorage;
|
||||||
|
class TabReplays;
|
||||||
class TabAdmin;
|
class TabAdmin;
|
||||||
class TabMessage;
|
class TabMessage;
|
||||||
class TabUserLists;
|
class TabUserLists;
|
||||||
|
@ -21,6 +22,7 @@ class Event_GameJoined;
|
||||||
class Event_UserMessage;
|
class Event_UserMessage;
|
||||||
class ServerInfo_Room;
|
class ServerInfo_Room;
|
||||||
class ServerInfo_User;
|
class ServerInfo_User;
|
||||||
|
class GameReplay;
|
||||||
|
|
||||||
class CloseButton : public QAbstractButton {
|
class CloseButton : public QAbstractButton {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -44,6 +46,7 @@ private:
|
||||||
TabServer *tabServer;
|
TabServer *tabServer;
|
||||||
TabUserLists *tabUserLists;
|
TabUserLists *tabUserLists;
|
||||||
TabDeckStorage *tabDeckStorage;
|
TabDeckStorage *tabDeckStorage;
|
||||||
|
TabReplays *tabReplays;
|
||||||
TabAdmin *tabAdmin;
|
TabAdmin *tabAdmin;
|
||||||
QMap<int, TabRoom *> roomTabs;
|
QMap<int, TabRoom *> roomTabs;
|
||||||
QMap<int, TabGame *> gameTabs;
|
QMap<int, TabGame *> gameTabs;
|
||||||
|
@ -77,6 +80,7 @@ private slots:
|
||||||
void addRoomTab(const ServerInfo_Room &info, bool setCurrent);
|
void addRoomTab(const ServerInfo_Room &info, bool setCurrent);
|
||||||
void roomLeft(TabRoom *tab);
|
void roomLeft(TabRoom *tab);
|
||||||
TabMessage *addMessageTab(const QString &userName, bool focus);
|
TabMessage *addMessageTab(const QString &userName, bool focus);
|
||||||
|
void openReplay(GameReplay *replay);
|
||||||
void processUserLeft(const QString &userName);
|
void processUserLeft(const QString &userName);
|
||||||
void processUserJoined(const QString &userName);
|
void processUserJoined(const QString &userName);
|
||||||
void talkLeft(TabMessage *tab);
|
void talkLeft(TabMessage *tab);
|
||||||
|
|
|
@ -12,6 +12,7 @@ SET(PROTO_FILES
|
||||||
command_deck_del_dir.proto
|
command_deck_del_dir.proto
|
||||||
command_deck_del.proto
|
command_deck_del.proto
|
||||||
command_deck_download.proto
|
command_deck_download.proto
|
||||||
|
command_deck_list.proto
|
||||||
command_deck_new_dir.proto
|
command_deck_new_dir.proto
|
||||||
command_deck_select.proto
|
command_deck_select.proto
|
||||||
command_deck_upload.proto
|
command_deck_upload.proto
|
||||||
|
@ -29,6 +30,8 @@ SET(PROTO_FILES
|
||||||
command_mulligan.proto
|
command_mulligan.proto
|
||||||
command_next_turn.proto
|
command_next_turn.proto
|
||||||
command_ready_start.proto
|
command_ready_start.proto
|
||||||
|
command_replay_list.proto
|
||||||
|
command_replay_download.proto
|
||||||
command_reveal_cards.proto
|
command_reveal_cards.proto
|
||||||
command_roll_die.proto
|
command_roll_die.proto
|
||||||
command_set_active_phase.proto
|
command_set_active_phase.proto
|
||||||
|
@ -107,6 +110,8 @@ SET(PROTO_FILES
|
||||||
response_join_room.proto
|
response_join_room.proto
|
||||||
response_list_users.proto
|
response_list_users.proto
|
||||||
response_login.proto
|
response_login.proto
|
||||||
|
response_replay_download.proto
|
||||||
|
response_replay_list.proto
|
||||||
response.proto
|
response.proto
|
||||||
room_commands.proto
|
room_commands.proto
|
||||||
room_event.proto
|
room_event.proto
|
||||||
|
@ -120,6 +125,7 @@ SET(PROTO_FILES
|
||||||
serverinfo_playerping.proto
|
serverinfo_playerping.proto
|
||||||
serverinfo_playerproperties.proto
|
serverinfo_playerproperties.proto
|
||||||
serverinfo_player.proto
|
serverinfo_player.proto
|
||||||
|
serverinfo_replay.proto
|
||||||
serverinfo_room.proto
|
serverinfo_room.proto
|
||||||
serverinfo_user.proto
|
serverinfo_user.proto
|
||||||
serverinfo_zone.proto
|
serverinfo_zone.proto
|
||||||
|
|
7
common/pb/command_deck_list.proto
Normal file
7
common/pb/command_deck_list.proto
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import "session_commands.proto";
|
||||||
|
|
||||||
|
message Command_DeckList {
|
||||||
|
extend SessionCommand {
|
||||||
|
optional Command_DeckList ext = 1008;
|
||||||
|
}
|
||||||
|
}
|
8
common/pb/command_replay_download.proto
Normal file
8
common/pb/command_replay_download.proto
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import "session_commands.proto";
|
||||||
|
|
||||||
|
message Command_ReplayDownload {
|
||||||
|
extend SessionCommand {
|
||||||
|
optional Command_ReplayDownload ext = 1101;
|
||||||
|
}
|
||||||
|
optional sint32 game_id = 1 [default = -1];
|
||||||
|
}
|
7
common/pb/command_replay_list.proto
Normal file
7
common/pb/command_replay_list.proto
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import "session_commands.proto";
|
||||||
|
|
||||||
|
message Command_ReplayList {
|
||||||
|
extend SessionCommand {
|
||||||
|
optional Command_ReplayList ext = 1100;
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ message Response {
|
||||||
RespWouldOverwriteOldSession = 17;
|
RespWouldOverwriteOldSession = 17;
|
||||||
RespChatFlood = 18;
|
RespChatFlood = 18;
|
||||||
RespUserIsBanned = 19;
|
RespUserIsBanned = 19;
|
||||||
|
RespAccessDenied = 20;
|
||||||
}
|
}
|
||||||
enum ResponseType {
|
enum ResponseType {
|
||||||
JOIN_ROOM = 1000;
|
JOIN_ROOM = 1000;
|
||||||
|
@ -31,6 +32,8 @@ message Response {
|
||||||
DECK_LIST = 1006;
|
DECK_LIST = 1006;
|
||||||
DECK_DOWNLOAD = 1007;
|
DECK_DOWNLOAD = 1007;
|
||||||
DECK_UPLOAD = 1008;
|
DECK_UPLOAD = 1008;
|
||||||
|
REPLAY_LIST = 1100;
|
||||||
|
REPLAY_DOWNLOAD = 1101;
|
||||||
}
|
}
|
||||||
required uint64 cmd_id = 1;
|
required uint64 cmd_id = 1;
|
||||||
optional ResponseCode response_code = 2;
|
optional ResponseCode response_code = 2;
|
||||||
|
|
9
common/pb/response_replay_download.proto
Normal file
9
common/pb/response_replay_download.proto
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import "response.proto";
|
||||||
|
|
||||||
|
message Response_ReplayDownload {
|
||||||
|
extend Response {
|
||||||
|
optional Response_ReplayDownload ext = 1101;
|
||||||
|
}
|
||||||
|
optional bytes replay_data = 1;
|
||||||
|
}
|
||||||
|
|
9
common/pb/response_replay_list.proto
Normal file
9
common/pb/response_replay_list.proto
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import "response.proto";
|
||||||
|
import "serverinfo_replay.proto";
|
||||||
|
|
||||||
|
message Response_ReplayList {
|
||||||
|
extend Response {
|
||||||
|
optional Response_ReplayList ext = 1100;
|
||||||
|
}
|
||||||
|
repeated ServerInfo_Replay replay_list = 1;
|
||||||
|
}
|
9
common/pb/serverinfo_replay.proto
Normal file
9
common/pb/serverinfo_replay.proto
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
message ServerInfo_Replay {
|
||||||
|
optional sint32 game_id = 1 [default = -1];
|
||||||
|
optional string room_name = 2;
|
||||||
|
optional uint32 time_started = 3;
|
||||||
|
optional uint32 length = 4;
|
||||||
|
optional string game_name = 5;
|
||||||
|
optional string replay_name = 6;
|
||||||
|
repeated string player_names = 7;
|
||||||
|
}
|
|
@ -18,4 +18,5 @@ message ServerInfo_User {
|
||||||
optional Gender gender = 5 [default = GenderUnknown];
|
optional Gender gender = 5 [default = GenderUnknown];
|
||||||
optional string country = 6;
|
optional string country = 6;
|
||||||
optional bytes avatar_bmp = 7;
|
optional bytes avatar_bmp = 7;
|
||||||
|
optional sint32 id = 8 [default = -1];
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@ message SessionCommand {
|
||||||
DECK_UPLOAD = 1013;
|
DECK_UPLOAD = 1013;
|
||||||
LIST_ROOMS = 1014;
|
LIST_ROOMS = 1014;
|
||||||
JOIN_ROOM = 1015;
|
JOIN_ROOM = 1015;
|
||||||
|
REPLAY_LIST = 1100;
|
||||||
|
REPLAY_DOWNLOAD = 1101;
|
||||||
}
|
}
|
||||||
extensions 100 to max;
|
extensions 100 to max;
|
||||||
}
|
}
|
||||||
|
@ -78,12 +80,6 @@ message Command_RemoveFromList {
|
||||||
optional string user_name = 2;
|
optional string user_name = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Command_DeckList {
|
|
||||||
extend SessionCommand {
|
|
||||||
optional Command_DeckList ext = 1008;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message Command_ListRooms {
|
message Command_ListRooms {
|
||||||
extend SessionCommand {
|
extend SessionCommand {
|
||||||
optional Command_ListRooms ext = 1014;
|
optional Command_ListRooms ext = 1014;
|
||||||
|
|
|
@ -58,7 +58,7 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString
|
||||||
if ((authState == NotLoggedIn) || (authState == UserIsBanned))
|
if ((authState == NotLoggedIn) || (authState == UserIsBanned))
|
||||||
return authState;
|
return authState;
|
||||||
|
|
||||||
ServerInfo_User data = getUserData(name);
|
ServerInfo_User data = 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
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ public:
|
||||||
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 void storeGameInformation(int secondsElapsed, const QStringList &allPlayersEver, const GameReplay &replay) { }
|
virtual void storeGameInformation(int secondsElapsed, const QSet<QString> &allPlayersEver, const QSet<QString> &allSpectatorsEver, const GameReplay &replay) { }
|
||||||
protected:
|
protected:
|
||||||
void prepareDestroy();
|
void prepareDestroy();
|
||||||
QList<Server_ProtocolHandler *> clients;
|
QList<Server_ProtocolHandler *> clients;
|
||||||
|
@ -59,7 +59,7 @@ protected:
|
||||||
virtual void endSession(int sessionId) { }
|
virtual void endSession(int sessionId) { }
|
||||||
virtual bool userExists(const QString &user) { return false; }
|
virtual bool userExists(const QString &user) { return false; }
|
||||||
virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reason) { return UnknownUser; }
|
virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reason) { return UnknownUser; }
|
||||||
virtual ServerInfo_User getUserData(const QString &name) = 0;
|
virtual ServerInfo_User getUserData(const QString &name, bool withId = false) = 0;
|
||||||
int getUsersCount() const;
|
int getUsersCount() const;
|
||||||
int getGamesCount() const;
|
int getGamesCount() const;
|
||||||
int nextGameId;
|
int nextGameId;
|
||||||
|
|
|
@ -48,11 +48,11 @@ Server_Game::Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QS
|
||||||
: QObject(), room(_room), hostId(0), creatorInfo(new ServerInfo_User(_creator->copyUserInfo(false))), gameStarted(false), gameId(_gameId), description(_description), password(_password), maxPlayers(_maxPlayers), gameTypes(_gameTypes), activePlayer(-1), activePhase(-1), onlyBuddies(_onlyBuddies), onlyRegistered(_onlyRegistered), spectatorsAllowed(_spectatorsAllowed), spectatorsNeedPassword(_spectatorsNeedPassword), spectatorsCanTalk(_spectatorsCanTalk), spectatorsSeeEverything(_spectatorsSeeEverything), inactivityCounter(0), secondsElapsed(0), startTime(QDateTime::currentDateTime()), gameMutex(QMutex::Recursive)
|
: QObject(), room(_room), hostId(0), creatorInfo(new ServerInfo_User(_creator->copyUserInfo(false))), gameStarted(false), gameId(_gameId), description(_description), password(_password), maxPlayers(_maxPlayers), gameTypes(_gameTypes), activePlayer(-1), activePhase(-1), onlyBuddies(_onlyBuddies), onlyRegistered(_onlyRegistered), spectatorsAllowed(_spectatorsAllowed), spectatorsNeedPassword(_spectatorsNeedPassword), spectatorsCanTalk(_spectatorsCanTalk), spectatorsSeeEverything(_spectatorsSeeEverything), inactivityCounter(0), secondsElapsed(0), startTime(QDateTime::currentDateTime()), gameMutex(QMutex::Recursive)
|
||||||
{
|
{
|
||||||
replay = new GameReplay;
|
replay = new GameReplay;
|
||||||
replay->mutable_game_info()->CopyFrom(getInfo());
|
|
||||||
|
|
||||||
connect(this, SIGNAL(sigStartGameIfReady()), this, SLOT(doStartGameIfReady()), Qt::QueuedConnection);
|
connect(this, SIGNAL(sigStartGameIfReady()), this, SLOT(doStartGameIfReady()), Qt::QueuedConnection);
|
||||||
|
|
||||||
addPlayer(_creator, false, false);
|
addPlayer(_creator, false, false);
|
||||||
|
replay->mutable_game_info()->CopyFrom(getInfo());
|
||||||
|
|
||||||
if (room->getServer()->getGameShouldPing()) {
|
if (room->getServer()->getGameShouldPing()) {
|
||||||
pingClock = new QTimer(this);
|
pingClock = new QTimer(this);
|
||||||
|
@ -80,7 +80,7 @@ Server_Game::~Server_Game()
|
||||||
gameMutex.unlock();
|
gameMutex.unlock();
|
||||||
room->roomMutex.unlock();
|
room->roomMutex.unlock();
|
||||||
|
|
||||||
room->getServer()->storeGameInformation(secondsElapsed, allPlayersEver.toList(), *replay);
|
room->getServer()->storeGameInformation(secondsElapsed, allPlayersEver, allSpectatorsEver, *replay);
|
||||||
delete replay;
|
delete replay;
|
||||||
|
|
||||||
qDebug() << "Server_Game destructor: gameId=" << gameId;
|
qDebug() << "Server_Game destructor: gameId=" << gameId;
|
||||||
|
@ -324,7 +324,10 @@ Server_Player *Server_Game::addPlayer(Server_ProtocolHandler *handler, bool spec
|
||||||
joinEvent.mutable_player_properties()->CopyFrom(newPlayer->getProperties(true));
|
joinEvent.mutable_player_properties()->CopyFrom(newPlayer->getProperties(true));
|
||||||
sendGameEventContainer(prepareGameEvent(joinEvent, -1));
|
sendGameEventContainer(prepareGameEvent(joinEvent, -1));
|
||||||
|
|
||||||
allPlayersEver.insert(QString::fromStdString(newPlayer->getUserInfo()->name()));
|
if (spectator)
|
||||||
|
allSpectatorsEver.insert(QString::fromStdString(newPlayer->getUserInfo()->name()));
|
||||||
|
else
|
||||||
|
allPlayersEver.insert(QString::fromStdString(newPlayer->getUserInfo()->name()));
|
||||||
players.insert(playerId, newPlayer);
|
players.insert(playerId, newPlayer);
|
||||||
if (newPlayer->getUserInfo()->name() == creatorInfo->name()) {
|
if (newPlayer->getUserInfo()->name() == creatorInfo->name()) {
|
||||||
hostId = playerId;
|
hostId = playerId;
|
||||||
|
|
|
@ -45,7 +45,7 @@ private:
|
||||||
int hostId;
|
int hostId;
|
||||||
ServerInfo_User *creatorInfo;
|
ServerInfo_User *creatorInfo;
|
||||||
QMap<int, Server_Player *> players;
|
QMap<int, Server_Player *> players;
|
||||||
QSet<QString> allPlayersEver;
|
QSet<QString> allPlayersEver, allSpectatorsEver;
|
||||||
bool gameStarted;
|
bool gameStarted;
|
||||||
int gameId;
|
int gameId;
|
||||||
QString description;
|
QString description;
|
||||||
|
|
|
@ -42,11 +42,14 @@
|
||||||
#include "pb/command_shuffle.pb.h"
|
#include "pb/command_shuffle.pb.h"
|
||||||
#include "pb/command_stop_dump_zone.pb.h"
|
#include "pb/command_stop_dump_zone.pb.h"
|
||||||
#include "pb/command_undo_draw.pb.h"
|
#include "pb/command_undo_draw.pb.h"
|
||||||
|
#include "pb/command_deck_list.pb.h"
|
||||||
#include "pb/command_deck_upload.pb.h"
|
#include "pb/command_deck_upload.pb.h"
|
||||||
#include "pb/command_deck_download.pb.h"
|
#include "pb/command_deck_download.pb.h"
|
||||||
#include "pb/command_deck_new_dir.pb.h"
|
#include "pb/command_deck_new_dir.pb.h"
|
||||||
#include "pb/command_deck_del_dir.pb.h"
|
#include "pb/command_deck_del_dir.pb.h"
|
||||||
#include "pb/command_deck_del.pb.h"
|
#include "pb/command_deck_del.pb.h"
|
||||||
|
#include "pb/command_replay_list.pb.h"
|
||||||
|
#include "pb/command_replay_download.pb.h"
|
||||||
#include "pb/response.pb.h"
|
#include "pb/response.pb.h"
|
||||||
#include "pb/response_login.pb.h"
|
#include "pb/response_login.pb.h"
|
||||||
#include "pb/response_list_users.pb.h"
|
#include "pb/response_list_users.pb.h"
|
||||||
|
@ -137,8 +140,10 @@ ServerInfo_User Server_ProtocolHandler::copyUserInfo(bool complete, bool moderat
|
||||||
ServerInfo_User result;
|
ServerInfo_User result;
|
||||||
if (userInfo) {
|
if (userInfo) {
|
||||||
result.CopyFrom(*userInfo);
|
result.CopyFrom(*userInfo);
|
||||||
if (!moderatorInfo)
|
if (!moderatorInfo) {
|
||||||
result.clear_address();
|
result.clear_address();
|
||||||
|
result.clear_id();
|
||||||
|
}
|
||||||
if (!complete)
|
if (!complete)
|
||||||
result.clear_avatar_bmp();
|
result.clear_avatar_bmp();
|
||||||
}
|
}
|
||||||
|
@ -234,6 +239,8 @@ Response::ResponseCode Server_ProtocolHandler::processSessionCommandContainer(co
|
||||||
case SessionCommand::DECK_DEL: resp = cmdDeckDel(sc.GetExtension(Command_DeckDel::ext), rc); break;
|
case SessionCommand::DECK_DEL: resp = cmdDeckDel(sc.GetExtension(Command_DeckDel::ext), rc); break;
|
||||||
case SessionCommand::DECK_UPLOAD: resp = cmdDeckUpload(sc.GetExtension(Command_DeckUpload::ext), rc); break;
|
case SessionCommand::DECK_UPLOAD: resp = cmdDeckUpload(sc.GetExtension(Command_DeckUpload::ext), rc); break;
|
||||||
case SessionCommand::DECK_DOWNLOAD: resp = cmdDeckDownload(sc.GetExtension(Command_DeckDownload::ext), rc); break;
|
case SessionCommand::DECK_DOWNLOAD: resp = cmdDeckDownload(sc.GetExtension(Command_DeckDownload::ext), rc); break;
|
||||||
|
case SessionCommand::REPLAY_LIST: resp = cmdReplayList(sc.GetExtension(Command_ReplayList::ext), rc); break;
|
||||||
|
case SessionCommand::REPLAY_DOWNLOAD: resp = cmdReplayDownload(sc.GetExtension(Command_ReplayDownload::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;
|
||||||
|
|
|
@ -39,6 +39,8 @@ class Command_DeckDelDir;
|
||||||
class Command_DeckDel;
|
class Command_DeckDel;
|
||||||
class Command_DeckDownload;
|
class Command_DeckDownload;
|
||||||
class Command_DeckUpload;
|
class Command_DeckUpload;
|
||||||
|
class Command_ReplayList;
|
||||||
|
class Command_ReplayDownload;
|
||||||
class Command_ListRooms;
|
class Command_ListRooms;
|
||||||
class Command_JoinRoom;
|
class Command_JoinRoom;
|
||||||
class Command_LeaveRoom;
|
class Command_LeaveRoom;
|
||||||
|
@ -119,6 +121,8 @@ private:
|
||||||
virtual Response::ResponseCode cmdDeckDel(const Command_DeckDel &cmd, ResponseContainer &rc) = 0;
|
virtual Response::ResponseCode cmdDeckDel(const Command_DeckDel &cmd, ResponseContainer &rc) = 0;
|
||||||
virtual Response::ResponseCode cmdDeckUpload(const Command_DeckUpload &cmd, ResponseContainer &rc) = 0;
|
virtual Response::ResponseCode cmdDeckUpload(const Command_DeckUpload &cmd, ResponseContainer &rc) = 0;
|
||||||
virtual Response::ResponseCode cmdDeckDownload(const Command_DeckDownload &cmd, ResponseContainer &rc) = 0;
|
virtual Response::ResponseCode cmdDeckDownload(const Command_DeckDownload &cmd, ResponseContainer &rc) = 0;
|
||||||
|
virtual Response::ResponseCode cmdReplayList(const Command_ReplayList &cmd, ResponseContainer &rc) = 0;
|
||||||
|
virtual Response::ResponseCode cmdReplayDownload(const Command_ReplayDownload &cmd, ResponseContainer &rc) = 0;
|
||||||
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);
|
||||||
|
|
|
@ -37,6 +37,7 @@ public:
|
||||||
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 QMap<int, Server_Game *> &getGames() const { return games; }
|
const QMap<int, Server_Game *> &getGames() const { return games; }
|
||||||
Server *getServer() const;
|
Server *getServer() const;
|
||||||
ServerInfo_Room getInfo(bool complete, bool showGameTypes = false, bool updating = false) const;
|
ServerInfo_Room getInfo(bool complete, bool showGameTypes = false, bool updating = false) const;
|
||||||
|
|
|
@ -323,29 +323,31 @@ bool Servatrice::isInIgnoreList(const QString &whoseList, const QString &who)
|
||||||
return query.next();
|
return query.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerInfo_User Servatrice::evalUserQueryResult(const QSqlQuery &query, bool complete)
|
ServerInfo_User Servatrice::evalUserQueryResult(const QSqlQuery &query, bool complete, bool withId)
|
||||||
{
|
{
|
||||||
ServerInfo_User result;
|
ServerInfo_User result;
|
||||||
|
|
||||||
result.set_name(query.value(0).toString().toStdString());
|
if (withId)
|
||||||
|
result.set_id(query.value(0).toInt());
|
||||||
|
result.set_name(query.value(1).toString().toStdString());
|
||||||
|
|
||||||
const QString country = query.value(4).toString();
|
const QString country = query.value(5).toString();
|
||||||
if (!country.isEmpty())
|
if (!country.isEmpty())
|
||||||
result.set_country(country.toStdString());
|
result.set_country(country.toStdString());
|
||||||
|
|
||||||
if (complete) {
|
if (complete) {
|
||||||
const QByteArray avatarBmp = query.value(5).toByteArray();
|
const QByteArray avatarBmp = query.value(6).toByteArray();
|
||||||
if (avatarBmp.size())
|
if (avatarBmp.size())
|
||||||
result.set_avatar_bmp(avatarBmp.data(), avatarBmp.size());
|
result.set_avatar_bmp(avatarBmp.data(), avatarBmp.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString genderStr = query.value(3).toString();
|
const QString genderStr = query.value(4).toString();
|
||||||
if (genderStr == "m")
|
if (genderStr == "m")
|
||||||
result.set_gender(ServerInfo_User::Male);
|
result.set_gender(ServerInfo_User::Male);
|
||||||
else if (genderStr == "f")
|
else if (genderStr == "f")
|
||||||
result.set_gender(ServerInfo_User::Female);
|
result.set_gender(ServerInfo_User::Female);
|
||||||
|
|
||||||
const int is_admin = query.value(1).toInt();
|
const int is_admin = query.value(2).toInt();
|
||||||
int userLevel = ServerInfo_User::IsUser | ServerInfo_User::IsRegistered;
|
int userLevel = ServerInfo_User::IsUser | ServerInfo_User::IsRegistered;
|
||||||
if (is_admin == 1)
|
if (is_admin == 1)
|
||||||
userLevel |= ServerInfo_User::IsAdmin | ServerInfo_User::IsModerator;
|
userLevel |= ServerInfo_User::IsAdmin | ServerInfo_User::IsModerator;
|
||||||
|
@ -353,14 +355,14 @@ ServerInfo_User Servatrice::evalUserQueryResult(const QSqlQuery &query, bool com
|
||||||
userLevel |= ServerInfo_User::IsModerator;
|
userLevel |= ServerInfo_User::IsModerator;
|
||||||
result.set_user_level(userLevel);
|
result.set_user_level(userLevel);
|
||||||
|
|
||||||
const QString realName = query.value(2).toString();
|
const QString realName = query.value(3).toString();
|
||||||
if (!realName.isEmpty())
|
if (!realName.isEmpty())
|
||||||
result.set_real_name(realName.toStdString());
|
result.set_real_name(realName.toStdString());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerInfo_User Servatrice::getUserData(const QString &name)
|
ServerInfo_User Servatrice::getUserData(const QString &name, bool withId)
|
||||||
{
|
{
|
||||||
ServerInfo_User result;
|
ServerInfo_User result;
|
||||||
result.set_name(name.toStdString());
|
result.set_name(name.toStdString());
|
||||||
|
@ -372,13 +374,13 @@ ServerInfo_User Servatrice::getUserData(const QString &name)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare("select name, admin, realname, gender, country, avatar_bmp from " + dbPrefix + "_users where name = :name and active = 1");
|
query.prepare("select id, name, admin, realname, gender, country, avatar_bmp from " + dbPrefix + "_users where name = :name and active = 1");
|
||||||
query.bindValue(":name", name);
|
query.bindValue(":name", name);
|
||||||
if (!execSqlQuery(query))
|
if (!execSqlQuery(query))
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if (query.next())
|
if (query.next())
|
||||||
return evalUserQueryResult(query, true);
|
return evalUserQueryResult(query, true, withId);
|
||||||
else
|
else
|
||||||
return result;
|
return result;
|
||||||
} else
|
} else
|
||||||
|
@ -447,7 +449,7 @@ QMap<QString, ServerInfo_User> Servatrice::getBuddyList(const QString &name)
|
||||||
checkSql();
|
checkSql();
|
||||||
|
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare("select a.name, a.admin, a.realname, a.gender, a.country from " + dbPrefix + "_users a left join " + dbPrefix + "_buddylist b on a.id = b.id_user2 left join " + dbPrefix + "_users c on b.id_user1 = c.id where c.name = :name");
|
query.prepare("select a.id, a.name, a.admin, a.realname, a.gender, a.country from " + dbPrefix + "_users a left join " + dbPrefix + "_buddylist b on a.id = b.id_user2 left join " + dbPrefix + "_users c on b.id_user1 = c.id where c.name = :name");
|
||||||
query.bindValue(":name", name);
|
query.bindValue(":name", name);
|
||||||
if (!execSqlQuery(query))
|
if (!execSqlQuery(query))
|
||||||
return result;
|
return result;
|
||||||
|
@ -469,7 +471,7 @@ QMap<QString, ServerInfo_User> Servatrice::getIgnoreList(const QString &name)
|
||||||
checkSql();
|
checkSql();
|
||||||
|
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare("select a.name, a.admin, a.realname, a.gender, a.country from " + dbPrefix + "_users a left join " + dbPrefix + "_ignorelist b on a.id = b.id_user2 left join " + dbPrefix + "_users c on b.id_user1 = c.id where c.name = :name");
|
query.prepare("select a.id, a.name, a.admin, a.realname, a.gender, a.country from " + dbPrefix + "_users a left join " + dbPrefix + "_ignorelist b on a.id = b.id_user2 left join " + dbPrefix + "_users c on b.id_user1 = c.id where c.name = :name");
|
||||||
query.bindValue(":name", name);
|
query.bindValue(":name", name);
|
||||||
if (!execSqlQuery(query))
|
if (!execSqlQuery(query))
|
||||||
return result;
|
return result;
|
||||||
|
@ -536,11 +538,14 @@ void Servatrice::statusUpdate()
|
||||||
execSqlQuery(query);
|
execSqlQuery(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Servatrice::storeGameInformation(int secondsElapsed, const QStringList &allPlayersEver, const GameReplay &replay)
|
void Servatrice::storeGameInformation(int secondsElapsed, const QSet<QString> &allPlayersEver, const QSet<QString> &allSpectatorsEver, const GameReplay &replay)
|
||||||
{
|
{
|
||||||
|
Server_Room *room = rooms.value(replay.game_info().room_id());
|
||||||
|
|
||||||
|
const QStringList &allGameTypes = room->getGameTypes();
|
||||||
QStringList gameTypes;
|
QStringList gameTypes;
|
||||||
for (int i = replay.game_info().game_types_size() - 1; i >= 0; --i)
|
for (int i = replay.game_info().game_types_size() - 1; i >= 0; --i)
|
||||||
gameTypes.append(QString::number(replay.game_info().game_types(i)));
|
gameTypes.append(allGameTypes[replay.game_info().game_types(i)]);
|
||||||
|
|
||||||
QByteArray replayBlob;
|
QByteArray replayBlob;
|
||||||
const unsigned int size = replay.ByteSize();
|
const unsigned int size = replay.ByteSize();
|
||||||
|
@ -552,29 +557,48 @@ void Servatrice::storeGameInformation(int secondsElapsed, const QStringList &all
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QSqlQuery query1;
|
QSqlQuery query1;
|
||||||
query1.prepare("insert into " + dbPrefix + "_games (id_room, id, descr, creator_name, password, game_types, player_count, time_started, time_finished, replay) values (:id_room, :id_game, :descr, :creator_name, :password, :game_types, :player_count, date_sub(now(), interval :seconds second), now(), :replay)");
|
query1.prepare("insert into " + dbPrefix + "_games (room_name, id, descr, creator_name, password, game_types, player_count, time_started, time_finished, replay) values (:id_room, :id_game, :descr, :creator_name, :password, :game_types, :player_count, date_sub(now(), interval :seconds second), now(), :replay)");
|
||||||
query1.bindValue(":id_room", replay.game_info().room_id());
|
query1.bindValue(":room_name", room->getName());
|
||||||
query1.bindValue(":id_game", replay.game_info().game_id());
|
query1.bindValue(":id_game", replay.game_info().game_id());
|
||||||
query1.bindValue(":descr", QString::fromStdString(replay.game_info().description()));
|
query1.bindValue(":descr", QString::fromStdString(replay.game_info().description()));
|
||||||
query1.bindValue(":creator_name", QString::fromStdString(replay.game_info().creator_info().name()));
|
query1.bindValue(":creator_name", QString::fromStdString(replay.game_info().creator_info().name()));
|
||||||
query1.bindValue(":password", replay.game_info().with_password() ? 1 : 0);
|
query1.bindValue(":password", replay.game_info().with_password() ? 1 : 0);
|
||||||
query1.bindValue(":game_types", gameTypes.isEmpty() ? QString("") : gameTypes.join(","));
|
query1.bindValue(":game_types", gameTypes.isEmpty() ? QString("") : gameTypes.join(", "));
|
||||||
query1.bindValue(":player_count", replay.game_info().max_players());
|
query1.bindValue(":player_count", replay.game_info().max_players());
|
||||||
query1.bindValue(":seconds", secondsElapsed);
|
query1.bindValue(":seconds", secondsElapsed);
|
||||||
query1.bindValue(":replay", replayBlob);
|
query1.bindValue(":replay", replayBlob);
|
||||||
if (!execSqlQuery(query1))
|
if (!execSqlQuery(query1))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
QVariantList gameIds1, playerNames, gameIds2, userIds, replayNames;
|
||||||
|
QSetIterator<QString> playerIterator(allPlayersEver);
|
||||||
|
while (playerIterator.hasNext()) {
|
||||||
|
gameIds1.append(replay.game_info().game_id());
|
||||||
|
playerNames.append(playerIterator.next());
|
||||||
|
}
|
||||||
|
QSet<QString> allUsersInGame = allPlayersEver + allSpectatorsEver;
|
||||||
|
QSetIterator<QString> allUsersIterator(allUsersInGame);
|
||||||
|
while (allUsersIterator.hasNext()) {
|
||||||
|
int id = getUserIdInDB(allUsersIterator.next());
|
||||||
|
if (id == -1)
|
||||||
|
continue;
|
||||||
|
gameIds2.append(replay.game_info().game_id());
|
||||||
|
userIds.append(id);
|
||||||
|
replayNames.append(QString::fromStdString(replay.game_info().description()));
|
||||||
|
}
|
||||||
|
|
||||||
QSqlQuery query2;
|
QSqlQuery query2;
|
||||||
query2.prepare("insert into " + dbPrefix + "_games_players (id_game, player_name) values (:id_game, :player_name)");
|
query2.prepare("insert into " + dbPrefix + "_games_players (id_game, player_name) values (:id_game, :player_name)");
|
||||||
QVariantList gameIds, playerNames;
|
query2.bindValue(":id_game", gameIds1);
|
||||||
for (int i = allPlayersEver.size() - 1; i >= 0; --i) {
|
|
||||||
gameIds.append(replay.game_info().game_id());
|
|
||||||
playerNames.append(allPlayersEver[i]);
|
|
||||||
}
|
|
||||||
query2.bindValue(":id_game", gameIds);
|
|
||||||
query2.bindValue(":player_name", playerNames);
|
query2.bindValue(":player_name", playerNames);
|
||||||
query2.execBatch();
|
query2.execBatch();
|
||||||
|
|
||||||
|
QSqlQuery query3;
|
||||||
|
query3.prepare("insert into " + dbPrefix + "_replays_access (id_game, id_player, replay_name) values (:id_game, :id_player, :replay_name)");
|
||||||
|
query3.bindValue(":id_game", gameIds2);
|
||||||
|
query3.bindValue(":id_player", userIds);
|
||||||
|
query3.bindValue(":replay_name", replayNames);
|
||||||
|
query3.execBatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Servatrice::scheduleShutdown(const QString &reason, int minutes)
|
void Servatrice::scheduleShutdown(const QString &reason, int minutes)
|
||||||
|
|
|
@ -71,7 +71,7 @@ public:
|
||||||
bool getThreaded() const { return threaded; }
|
bool getThreaded() const { return threaded; }
|
||||||
QString getDbPrefix() const { return dbPrefix; }
|
QString getDbPrefix() const { return dbPrefix; }
|
||||||
void updateLoginMessage();
|
void updateLoginMessage();
|
||||||
ServerInfo_User getUserData(const QString &name);
|
ServerInfo_User getUserData(const QString &name, bool withId = false);
|
||||||
int getUsersWithAddress(const QHostAddress &address) const;
|
int getUsersWithAddress(const QHostAddress &address) const;
|
||||||
QList<ServerSocketInterface *> getUsersWithAddressAsList(const QHostAddress &address) const;
|
QList<ServerSocketInterface *> getUsersWithAddressAsList(const QHostAddress &address) const;
|
||||||
QMap<QString, ServerInfo_User> getBuddyList(const QString &name);
|
QMap<QString, ServerInfo_User> getBuddyList(const QString &name);
|
||||||
|
@ -82,7 +82,7 @@ public:
|
||||||
void incTxBytes(quint64 num);
|
void incTxBytes(quint64 num);
|
||||||
void incRxBytes(quint64 num);
|
void incRxBytes(quint64 num);
|
||||||
int getUserIdInDB(const QString &name);
|
int getUserIdInDB(const QString &name);
|
||||||
void storeGameInformation(int secondsElapsed, const QStringList &allPlayersEver, const GameReplay &replay);
|
void storeGameInformation(int secondsElapsed, const QSet<QString> &allPlayersEver, const QSet<QString> &allSpectatorsEver, const GameReplay &replay);
|
||||||
protected:
|
protected:
|
||||||
int startSession(const QString &userName, const QString &address);
|
int startSession(const QString &userName, const QString &address);
|
||||||
void endSession(int sessionId);
|
void endSession(int sessionId);
|
||||||
|
@ -106,7 +106,7 @@ private:
|
||||||
quint64 txBytes, rxBytes;
|
quint64 txBytes, rxBytes;
|
||||||
int maxGameInactivityTime, maxPlayerInactivityTime;
|
int maxGameInactivityTime, maxPlayerInactivityTime;
|
||||||
int maxUsersPerAddress, messageCountingInterval, maxMessageCountPerInterval, maxMessageSizePerInterval, maxGamesPerUser;
|
int maxUsersPerAddress, messageCountingInterval, maxMessageCountPerInterval, maxMessageSizePerInterval, maxGamesPerUser;
|
||||||
ServerInfo_User evalUserQueryResult(const QSqlQuery &query, bool complete);
|
ServerInfo_User evalUserQueryResult(const QSqlQuery &query, bool complete, bool withId = false);
|
||||||
|
|
||||||
QString shutdownReason;
|
QString shutdownReason;
|
||||||
int shutdownMinutes;
|
int shutdownMinutes;
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
#include "pb/command_deck_new_dir.pb.h"
|
#include "pb/command_deck_new_dir.pb.h"
|
||||||
#include "pb/command_deck_del_dir.pb.h"
|
#include "pb/command_deck_del_dir.pb.h"
|
||||||
#include "pb/command_deck_del.pb.h"
|
#include "pb/command_deck_del.pb.h"
|
||||||
|
#include "pb/command_replay_list.pb.h"
|
||||||
|
#include "pb/command_replay_download.pb.h"
|
||||||
#include "pb/event_connection_closed.pb.h"
|
#include "pb/event_connection_closed.pb.h"
|
||||||
#include "pb/event_server_message.pb.h"
|
#include "pb/event_server_message.pb.h"
|
||||||
#include "pb/event_server_identification.pb.h"
|
#include "pb/event_server_identification.pb.h"
|
||||||
|
@ -42,6 +44,9 @@
|
||||||
#include "pb/response_deck_list.pb.h"
|
#include "pb/response_deck_list.pb.h"
|
||||||
#include "pb/response_deck_download.pb.h"
|
#include "pb/response_deck_download.pb.h"
|
||||||
#include "pb/response_deck_upload.pb.h"
|
#include "pb/response_deck_upload.pb.h"
|
||||||
|
#include "pb/response_replay_list.pb.h"
|
||||||
|
#include "pb/response_replay_download.pb.h"
|
||||||
|
#include "pb/serverinfo_replay.pb.h"
|
||||||
#include "pb/serverinfo_user.pb.h"
|
#include "pb/serverinfo_user.pb.h"
|
||||||
#include "pb/serverinfo_deckstorage.pb.h"
|
#include "pb/serverinfo_deckstorage.pb.h"
|
||||||
|
|
||||||
|
@ -175,7 +180,7 @@ Response::ResponseCode ServerSocketInterface::cmdAddToList(const Command_AddToLi
|
||||||
if (servatrice->isInIgnoreList(QString::fromStdString(userInfo->name()), user))
|
if (servatrice->isInIgnoreList(QString::fromStdString(userInfo->name()), user))
|
||||||
return Response::RespContextError;
|
return Response::RespContextError;
|
||||||
|
|
||||||
int id1 = servatrice->getUserIdInDB(QString::fromStdString(userInfo->name()));
|
int id1 = userInfo->id();
|
||||||
int id2 = servatrice->getUserIdInDB(user);
|
int id2 = servatrice->getUserIdInDB(user);
|
||||||
if (id2 < 0)
|
if (id2 < 0)
|
||||||
return Response::RespNameNotFound;
|
return Response::RespNameNotFound;
|
||||||
|
@ -216,7 +221,7 @@ Response::ResponseCode ServerSocketInterface::cmdRemoveFromList(const Command_Re
|
||||||
if (!servatrice->isInIgnoreList(QString::fromStdString(userInfo->name()), user))
|
if (!servatrice->isInIgnoreList(QString::fromStdString(userInfo->name()), user))
|
||||||
return Response::RespContextError;
|
return Response::RespContextError;
|
||||||
|
|
||||||
int id1 = servatrice->getUserIdInDB(QString::fromStdString(userInfo->name()));
|
int id1 = userInfo->id();
|
||||||
int id2 = servatrice->getUserIdInDB(user);
|
int id2 = servatrice->getUserIdInDB(user);
|
||||||
if (id2 < 0)
|
if (id2 < 0)
|
||||||
return Response::RespNameNotFound;
|
return Response::RespNameNotFound;
|
||||||
|
@ -485,6 +490,77 @@ Response::ResponseCode ServerSocketInterface::cmdDeckDownload(const Command_Deck
|
||||||
return Response::RespOk;
|
return Response::RespOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Response::ResponseCode ServerSocketInterface::cmdReplayList(const Command_ReplayList & /*cmd*/, ResponseContainer &rc)
|
||||||
|
{
|
||||||
|
if (authState != PasswordRight)
|
||||||
|
return Response::RespFunctionNotAllowed;
|
||||||
|
|
||||||
|
Response_ReplayList *re = new Response_ReplayList;
|
||||||
|
|
||||||
|
servatrice->dbMutex.lock();
|
||||||
|
QSqlQuery query1;
|
||||||
|
query1.prepare("select a.id_game, a.replay_name, b.room_name, b.time_started, b.time_finished, b.descr from cockatrice_replays_access a left join cockatrice_games b on b.id = a.id_game where a.id_player = :id_player");
|
||||||
|
query1.bindValue(":id_player", userInfo->id());
|
||||||
|
servatrice->execSqlQuery(query1);
|
||||||
|
while (query1.next()) {
|
||||||
|
ServerInfo_Replay *replayInfo = re->add_replay_list();
|
||||||
|
const int gameId = query1.value(0).toInt();
|
||||||
|
replayInfo->set_game_id(gameId);
|
||||||
|
replayInfo->set_room_name(query1.value(2).toString().toStdString());
|
||||||
|
const int timeStarted = query1.value(3).toDateTime().toTime_t();
|
||||||
|
const int timeFinished = query1.value(4).toDateTime().toTime_t();
|
||||||
|
replayInfo->set_time_started(timeStarted);
|
||||||
|
replayInfo->set_length(timeFinished - timeStarted);
|
||||||
|
replayInfo->set_game_name(query1.value(5).toString().toStdString());
|
||||||
|
replayInfo->set_replay_name(query1.value(1).toString().toStdString());
|
||||||
|
|
||||||
|
QSqlQuery query2;
|
||||||
|
query2.prepare("select player_name from cockatrice_games_players where id_game = :id_game");
|
||||||
|
query2.bindValue(":id_game", gameId);
|
||||||
|
servatrice->execSqlQuery(query2);
|
||||||
|
while (query2.next())
|
||||||
|
replayInfo->add_player_names(query2.value(0).toString().toStdString());
|
||||||
|
}
|
||||||
|
servatrice->dbMutex.unlock();
|
||||||
|
|
||||||
|
rc.setResponseExtension(re);
|
||||||
|
return Response::RespOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
Response::ResponseCode ServerSocketInterface::cmdReplayDownload(const Command_ReplayDownload &cmd, ResponseContainer &rc)
|
||||||
|
{
|
||||||
|
if (authState != PasswordRight)
|
||||||
|
return Response::RespFunctionNotAllowed;
|
||||||
|
|
||||||
|
QMutexLocker dbLocker(&servatrice->dbMutex);
|
||||||
|
|
||||||
|
QSqlQuery query1;
|
||||||
|
query1.prepare("select 1 from " + servatrice->getDbPrefix() + "_replays_access where id_game = :id_game and id_player = :id_player");
|
||||||
|
query1.bindValue(":id_game", cmd.game_id());
|
||||||
|
query1.bindValue(":id_player", userInfo->id());
|
||||||
|
if (!servatrice->execSqlQuery(query1))
|
||||||
|
return Response::RespInternalError;
|
||||||
|
if (!query1.next())
|
||||||
|
return Response::RespAccessDenied;
|
||||||
|
|
||||||
|
QSqlQuery query2;
|
||||||
|
query2.prepare("select replay from " + servatrice->getDbPrefix() + "_games where id = :id_game");
|
||||||
|
query2.bindValue(":id_game", cmd.game_id());
|
||||||
|
if (!servatrice->execSqlQuery(query2))
|
||||||
|
return Response::RespInternalError;
|
||||||
|
if (!query2.next())
|
||||||
|
return Response::RespNameNotFound;
|
||||||
|
|
||||||
|
QByteArray data = query2.value(0).toByteArray();
|
||||||
|
|
||||||
|
Response_ReplayDownload *re = new Response_ReplayDownload;
|
||||||
|
re->set_replay_data(data.data(), data.size());
|
||||||
|
rc.setResponseExtension(re);
|
||||||
|
|
||||||
|
return Response::RespOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// MODERATOR FUNCTIONS.
|
// MODERATOR FUNCTIONS.
|
||||||
// May be called by admins and moderators. Permission is checked by the calling function.
|
// May be called by admins and moderators. Permission is checked by the calling function.
|
||||||
|
|
||||||
|
@ -499,7 +575,7 @@ Response::ResponseCode ServerSocketInterface::cmdBanFromServer(const Command_Ban
|
||||||
query.prepare("insert into " + servatrice->getDbPrefix() + "_bans (user_name, ip_address, id_admin, time_from, minutes, reason, visible_reason) values(:user_name, :ip_address, :id_admin, NOW(), :minutes, :reason, :visible_reason)");
|
query.prepare("insert into " + servatrice->getDbPrefix() + "_bans (user_name, ip_address, id_admin, time_from, minutes, reason, visible_reason) values(:user_name, :ip_address, :id_admin, NOW(), :minutes, :reason, :visible_reason)");
|
||||||
query.bindValue(":user_name", userName);
|
query.bindValue(":user_name", userName);
|
||||||
query.bindValue(":ip_address", address);
|
query.bindValue(":ip_address", address);
|
||||||
query.bindValue(":id_admin", servatrice->getUserIdInDB(QString::fromStdString(userInfo->name())));
|
query.bindValue(":id_admin", userInfo->id());
|
||||||
query.bindValue(":minutes", minutes);
|
query.bindValue(":minutes", minutes);
|
||||||
query.bindValue(":reason", QString::fromStdString(cmd.reason()) + "\n");
|
query.bindValue(":reason", QString::fromStdString(cmd.reason()) + "\n");
|
||||||
query.bindValue(":visible_reason", QString::fromStdString(cmd.visible_reason()) + "\n");
|
query.bindValue(":visible_reason", QString::fromStdString(cmd.visible_reason()) + "\n");
|
||||||
|
|
|
@ -61,6 +61,8 @@ private:
|
||||||
Response::ResponseCode cmdDeckUpload(const Command_DeckUpload &cmd, ResponseContainer &rc);
|
Response::ResponseCode cmdDeckUpload(const Command_DeckUpload &cmd, ResponseContainer &rc);
|
||||||
DeckList *getDeckFromDatabase(int deckId);
|
DeckList *getDeckFromDatabase(int deckId);
|
||||||
Response::ResponseCode cmdDeckDownload(const Command_DeckDownload &cmd, ResponseContainer &rc);
|
Response::ResponseCode cmdDeckDownload(const Command_DeckDownload &cmd, ResponseContainer &rc);
|
||||||
|
Response::ResponseCode cmdReplayList(const Command_ReplayList &cmd, ResponseContainer &rc);
|
||||||
|
Response::ResponseCode cmdReplayDownload(const Command_ReplayDownload &cmd, ResponseContainer &rc);
|
||||||
Response::ResponseCode cmdBanFromServer(const Command_BanFromServer &cmd, ResponseContainer &rc);
|
Response::ResponseCode cmdBanFromServer(const Command_BanFromServer &cmd, ResponseContainer &rc);
|
||||||
Response::ResponseCode cmdShutdownServer(const Command_ShutdownServer &cmd, ResponseContainer &rc);
|
Response::ResponseCode cmdShutdownServer(const Command_ShutdownServer &cmd, ResponseContainer &rc);
|
||||||
Response::ResponseCode cmdUpdateServerMessage(const Command_UpdateServerMessage &cmd, ResponseContainer &rc);
|
Response::ResponseCode cmdUpdateServerMessage(const Command_UpdateServerMessage &cmd, ResponseContainer &rc);
|
||||||
|
|
Loading…
Reference in a new issue