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_game.cpp
|
||||
src/tab_deck_storage.cpp
|
||||
src/tab_replays.cpp
|
||||
src/tab_supervisor.cpp
|
||||
src/tab_admin.cpp
|
||||
src/tab_userlists.cpp
|
||||
|
@ -61,6 +62,7 @@ SET(cockatrice_SOURCES
|
|||
src/userlist.cpp
|
||||
src/userinfobox.cpp
|
||||
src/remotedecklist_treewidget.cpp
|
||||
src/remotereplaylist_treewidget.cpp
|
||||
src/deckview.cpp
|
||||
src/playerlistwidget.cpp
|
||||
src/pixmapgenerator.cpp
|
||||
|
@ -122,6 +124,7 @@ SET(cockatrice_HEADERS
|
|||
src/tab_message.h
|
||||
src/tab_game.h
|
||||
src/tab_deck_storage.h
|
||||
src/tab_replays.h
|
||||
src/tab_supervisor.h
|
||||
src/tab_admin.h
|
||||
src/tab_userlists.h
|
||||
|
@ -129,6 +132,7 @@ SET(cockatrice_HEADERS
|
|||
src/userlist.h
|
||||
src/userinfobox.h
|
||||
src/remotedecklist_treewidget.h
|
||||
src/remotereplaylist_treewidget.h
|
||||
src/deckview.h
|
||||
src/playerlistwidget.h
|
||||
src/settingscache.h
|
||||
|
|
|
@ -20,7 +20,7 @@ LocalServerInterface *LocalServer::newConnection()
|
|||
return lsi;
|
||||
}
|
||||
|
||||
ServerInfo_User LocalServer::getUserData(const QString &name)
|
||||
ServerInfo_User LocalServer::getUserData(const QString &name, bool /*withId*/)
|
||||
{
|
||||
ServerInfo_User result;
|
||||
result.set_name(name.toStdString());
|
||||
|
|
|
@ -14,7 +14,7 @@ public:
|
|||
|
||||
LocalServerInterface *newConnection();
|
||||
protected:
|
||||
ServerInfo_User getUserData(const QString &name);
|
||||
ServerInfo_User getUserData(const QString &name, bool withId = false);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -18,6 +18,8 @@ private:
|
|||
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 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 cmdShutdownServer(const Command_ShutdownServer & /*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);
|
||||
|
||||
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()))
|
||||
fullPixmap = QPixmap();
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "abstractclient.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/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 QTreeWidgetItem;
|
||||
class QGroupBox;
|
||||
class ProtocolResponse;
|
||||
class RemoteDeckList_TreeWidget;
|
||||
|
||||
class TabDeckStorage : public Tab {
|
||||
|
|
|
@ -957,6 +957,14 @@ CardItem *TabGame::getCard(int playerId, const QString &zoneName, int cardId) co
|
|||
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 *active = players.value(activePlayer, 0);
|
||||
|
|
|
@ -180,7 +180,7 @@ public:
|
|||
CardItem *getCard(int playerId, const QString &zoneName, int cardId) const;
|
||||
bool isHost() const { return hostId == localPlayerId; }
|
||||
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 getSpectatorsCanTalk() const { return spectatorsCanTalk; }
|
||||
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_game.h"
|
||||
#include "tab_deck_storage.h"
|
||||
#include "tab_replays.h"
|
||||
#include "tab_admin.h"
|
||||
#include "tab_message.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) {
|
||||
tabDeckStorage = new TabDeckStorage(this, client);
|
||||
myAddTab(tabDeckStorage);
|
||||
} else
|
||||
|
||||
tabReplays = new TabReplays(this, client);
|
||||
connect(tabReplays, SIGNAL(openReplay(GameReplay *)), this, SLOT(openReplay(GameReplay *)));
|
||||
myAddTab(tabReplays);
|
||||
} else {
|
||||
tabDeckStorage = 0;
|
||||
tabReplays = 0;
|
||||
}
|
||||
|
||||
if (userInfo->user_level() & ServerInfo_User::IsModerator) {
|
||||
tabAdmin = new TabAdmin(this, client, (userInfo->user_level() & ServerInfo_User::IsAdmin));
|
||||
|
@ -155,6 +162,7 @@ void TabSupervisor::startLocal(const QList<AbstractClient *> &_clients)
|
|||
{
|
||||
tabUserLists = 0;
|
||||
tabDeckStorage = 0;
|
||||
tabReplays = 0;
|
||||
tabAdmin = 0;
|
||||
userInfo = new ServerInfo_User;
|
||||
localClients = _clients;
|
||||
|
@ -183,10 +191,12 @@ void TabSupervisor::stop()
|
|||
tabUserLists->deleteLater();
|
||||
tabServer->deleteLater();
|
||||
tabDeckStorage->deleteLater();
|
||||
tabReplays->deleteLater();
|
||||
}
|
||||
tabUserLists = 0;
|
||||
tabServer = 0;
|
||||
tabDeckStorage = 0;
|
||||
tabReplays = 0;
|
||||
clear();
|
||||
|
||||
QMapIterator<int, TabRoom *> roomIterator(roomTabs);
|
||||
|
@ -306,6 +316,12 @@ TabMessage *TabSupervisor::addMessageTab(const QString &receiverName, bool focus
|
|||
return tab;
|
||||
}
|
||||
|
||||
void TabSupervisor::openReplay(GameReplay *replay)
|
||||
{
|
||||
TabGame *replayTab = new TabGame(replay);
|
||||
myAddTab(replayTab);
|
||||
}
|
||||
|
||||
void TabSupervisor::talkLeft(TabMessage *tab)
|
||||
{
|
||||
emit setMenu(0);
|
||||
|
|
|
@ -12,6 +12,7 @@ class TabServer;
|
|||
class TabRoom;
|
||||
class TabGame;
|
||||
class TabDeckStorage;
|
||||
class TabReplays;
|
||||
class TabAdmin;
|
||||
class TabMessage;
|
||||
class TabUserLists;
|
||||
|
@ -21,6 +22,7 @@ class Event_GameJoined;
|
|||
class Event_UserMessage;
|
||||
class ServerInfo_Room;
|
||||
class ServerInfo_User;
|
||||
class GameReplay;
|
||||
|
||||
class CloseButton : public QAbstractButton {
|
||||
Q_OBJECT
|
||||
|
@ -44,6 +46,7 @@ private:
|
|||
TabServer *tabServer;
|
||||
TabUserLists *tabUserLists;
|
||||
TabDeckStorage *tabDeckStorage;
|
||||
TabReplays *tabReplays;
|
||||
TabAdmin *tabAdmin;
|
||||
QMap<int, TabRoom *> roomTabs;
|
||||
QMap<int, TabGame *> gameTabs;
|
||||
|
@ -77,6 +80,7 @@ private slots:
|
|||
void addRoomTab(const ServerInfo_Room &info, bool setCurrent);
|
||||
void roomLeft(TabRoom *tab);
|
||||
TabMessage *addMessageTab(const QString &userName, bool focus);
|
||||
void openReplay(GameReplay *replay);
|
||||
void processUserLeft(const QString &userName);
|
||||
void processUserJoined(const QString &userName);
|
||||
void talkLeft(TabMessage *tab);
|
||||
|
|
|
@ -12,6 +12,7 @@ SET(PROTO_FILES
|
|||
command_deck_del_dir.proto
|
||||
command_deck_del.proto
|
||||
command_deck_download.proto
|
||||
command_deck_list.proto
|
||||
command_deck_new_dir.proto
|
||||
command_deck_select.proto
|
||||
command_deck_upload.proto
|
||||
|
@ -29,6 +30,8 @@ SET(PROTO_FILES
|
|||
command_mulligan.proto
|
||||
command_next_turn.proto
|
||||
command_ready_start.proto
|
||||
command_replay_list.proto
|
||||
command_replay_download.proto
|
||||
command_reveal_cards.proto
|
||||
command_roll_die.proto
|
||||
command_set_active_phase.proto
|
||||
|
@ -107,6 +110,8 @@ SET(PROTO_FILES
|
|||
response_join_room.proto
|
||||
response_list_users.proto
|
||||
response_login.proto
|
||||
response_replay_download.proto
|
||||
response_replay_list.proto
|
||||
response.proto
|
||||
room_commands.proto
|
||||
room_event.proto
|
||||
|
@ -120,6 +125,7 @@ SET(PROTO_FILES
|
|||
serverinfo_playerping.proto
|
||||
serverinfo_playerproperties.proto
|
||||
serverinfo_player.proto
|
||||
serverinfo_replay.proto
|
||||
serverinfo_room.proto
|
||||
serverinfo_user.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;
|
||||
RespChatFlood = 18;
|
||||
RespUserIsBanned = 19;
|
||||
RespAccessDenied = 20;
|
||||
}
|
||||
enum ResponseType {
|
||||
JOIN_ROOM = 1000;
|
||||
|
@ -31,6 +32,8 @@ message Response {
|
|||
DECK_LIST = 1006;
|
||||
DECK_DOWNLOAD = 1007;
|
||||
DECK_UPLOAD = 1008;
|
||||
REPLAY_LIST = 1100;
|
||||
REPLAY_DOWNLOAD = 1101;
|
||||
}
|
||||
required uint64 cmd_id = 1;
|
||||
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 string country = 6;
|
||||
optional bytes avatar_bmp = 7;
|
||||
optional sint32 id = 8 [default = -1];
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ message SessionCommand {
|
|||
DECK_UPLOAD = 1013;
|
||||
LIST_ROOMS = 1014;
|
||||
JOIN_ROOM = 1015;
|
||||
REPLAY_LIST = 1100;
|
||||
REPLAY_DOWNLOAD = 1101;
|
||||
}
|
||||
extensions 100 to max;
|
||||
}
|
||||
|
@ -78,12 +80,6 @@ message Command_RemoveFromList {
|
|||
optional string user_name = 2;
|
||||
}
|
||||
|
||||
message Command_DeckList {
|
||||
extend SessionCommand {
|
||||
optional Command_DeckList ext = 1008;
|
||||
}
|
||||
}
|
||||
|
||||
message Command_ListRooms {
|
||||
extend SessionCommand {
|
||||
optional Command_ListRooms ext = 1014;
|
||||
|
|
|
@ -58,7 +58,7 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString
|
|||
if ((authState == NotLoggedIn) || (authState == UserIsBanned))
|
||||
return authState;
|
||||
|
||||
ServerInfo_User data = getUserData(name);
|
||||
ServerInfo_User data = getUserData(name, true);
|
||||
data.set_address(session->getAddress().toStdString());
|
||||
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 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:
|
||||
void prepareDestroy();
|
||||
QList<Server_ProtocolHandler *> clients;
|
||||
|
@ -59,7 +59,7 @@ protected:
|
|||
virtual void endSession(int sessionId) { }
|
||||
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 ServerInfo_User getUserData(const QString &name) = 0;
|
||||
virtual ServerInfo_User getUserData(const QString &name, bool withId = false) = 0;
|
||||
int getUsersCount() const;
|
||||
int getGamesCount() const;
|
||||
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)
|
||||
{
|
||||
replay = new GameReplay;
|
||||
replay->mutable_game_info()->CopyFrom(getInfo());
|
||||
|
||||
connect(this, SIGNAL(sigStartGameIfReady()), this, SLOT(doStartGameIfReady()), Qt::QueuedConnection);
|
||||
|
||||
addPlayer(_creator, false, false);
|
||||
replay->mutable_game_info()->CopyFrom(getInfo());
|
||||
|
||||
if (room->getServer()->getGameShouldPing()) {
|
||||
pingClock = new QTimer(this);
|
||||
|
@ -80,7 +80,7 @@ Server_Game::~Server_Game()
|
|||
gameMutex.unlock();
|
||||
room->roomMutex.unlock();
|
||||
|
||||
room->getServer()->storeGameInformation(secondsElapsed, allPlayersEver.toList(), *replay);
|
||||
room->getServer()->storeGameInformation(secondsElapsed, allPlayersEver, allSpectatorsEver, *replay);
|
||||
delete replay;
|
||||
|
||||
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));
|
||||
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);
|
||||
if (newPlayer->getUserInfo()->name() == creatorInfo->name()) {
|
||||
hostId = playerId;
|
||||
|
|
|
@ -45,7 +45,7 @@ private:
|
|||
int hostId;
|
||||
ServerInfo_User *creatorInfo;
|
||||
QMap<int, Server_Player *> players;
|
||||
QSet<QString> allPlayersEver;
|
||||
QSet<QString> allPlayersEver, allSpectatorsEver;
|
||||
bool gameStarted;
|
||||
int gameId;
|
||||
QString description;
|
||||
|
|
|
@ -42,11 +42,14 @@
|
|||
#include "pb/command_shuffle.pb.h"
|
||||
#include "pb/command_stop_dump_zone.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_download.pb.h"
|
||||
#include "pb/command_deck_new_dir.pb.h"
|
||||
#include "pb/command_deck_del_dir.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_login.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;
|
||||
if (userInfo) {
|
||||
result.CopyFrom(*userInfo);
|
||||
if (!moderatorInfo)
|
||||
if (!moderatorInfo) {
|
||||
result.clear_address();
|
||||
result.clear_id();
|
||||
}
|
||||
if (!complete)
|
||||
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_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::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_USER_INFO: resp = cmdGetUserInfo(sc.GetExtension(Command_GetUserInfo::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_DeckDownload;
|
||||
class Command_DeckUpload;
|
||||
class Command_ReplayList;
|
||||
class Command_ReplayDownload;
|
||||
class Command_ListRooms;
|
||||
class Command_JoinRoom;
|
||||
class Command_LeaveRoom;
|
||||
|
@ -119,6 +121,8 @@ private:
|
|||
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 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 cmdGetUserInfo(const Command_GetUserInfo &cmd, ResponseContainer &rc);
|
||||
Response::ResponseCode cmdListRooms(const Command_ListRooms &cmd, ResponseContainer &rc);
|
||||
|
|
|
@ -37,6 +37,7 @@ public:
|
|||
QString getDescription() const { return description; }
|
||||
bool getAutoJoin() const { return autoJoin; }
|
||||
QString getJoinMessage() const { return joinMessage; }
|
||||
const QStringList &getGameTypes() const { return gameTypes; }
|
||||
const QMap<int, Server_Game *> &getGames() const { return games; }
|
||||
Server *getServer() 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();
|
||||
}
|
||||
|
||||
ServerInfo_User Servatrice::evalUserQueryResult(const QSqlQuery &query, bool complete)
|
||||
ServerInfo_User Servatrice::evalUserQueryResult(const QSqlQuery &query, bool complete, bool withId)
|
||||
{
|
||||
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())
|
||||
result.set_country(country.toStdString());
|
||||
|
||||
if (complete) {
|
||||
const QByteArray avatarBmp = query.value(5).toByteArray();
|
||||
const QByteArray avatarBmp = query.value(6).toByteArray();
|
||||
if (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")
|
||||
result.set_gender(ServerInfo_User::Male);
|
||||
else if (genderStr == "f")
|
||||
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;
|
||||
if (is_admin == 1)
|
||||
userLevel |= ServerInfo_User::IsAdmin | ServerInfo_User::IsModerator;
|
||||
|
@ -353,14 +355,14 @@ ServerInfo_User Servatrice::evalUserQueryResult(const QSqlQuery &query, bool com
|
|||
userLevel |= ServerInfo_User::IsModerator;
|
||||
result.set_user_level(userLevel);
|
||||
|
||||
const QString realName = query.value(2).toString();
|
||||
const QString realName = query.value(3).toString();
|
||||
if (!realName.isEmpty())
|
||||
result.set_real_name(realName.toStdString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ServerInfo_User Servatrice::getUserData(const QString &name)
|
||||
ServerInfo_User Servatrice::getUserData(const QString &name, bool withId)
|
||||
{
|
||||
ServerInfo_User result;
|
||||
result.set_name(name.toStdString());
|
||||
|
@ -372,13 +374,13 @@ ServerInfo_User Servatrice::getUserData(const QString &name)
|
|||
return result;
|
||||
|
||||
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);
|
||||
if (!execSqlQuery(query))
|
||||
return result;
|
||||
|
||||
if (query.next())
|
||||
return evalUserQueryResult(query, true);
|
||||
return evalUserQueryResult(query, true, withId);
|
||||
else
|
||||
return result;
|
||||
} else
|
||||
|
@ -447,7 +449,7 @@ QMap<QString, ServerInfo_User> Servatrice::getBuddyList(const QString &name)
|
|||
checkSql();
|
||||
|
||||
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);
|
||||
if (!execSqlQuery(query))
|
||||
return result;
|
||||
|
@ -469,7 +471,7 @@ QMap<QString, ServerInfo_User> Servatrice::getIgnoreList(const QString &name)
|
|||
checkSql();
|
||||
|
||||
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);
|
||||
if (!execSqlQuery(query))
|
||||
return result;
|
||||
|
@ -536,11 +538,14 @@ void Servatrice::statusUpdate()
|
|||
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;
|
||||
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;
|
||||
const unsigned int size = replay.ByteSize();
|
||||
|
@ -552,29 +557,48 @@ void Servatrice::storeGameInformation(int secondsElapsed, const QStringList &all
|
|||
return;
|
||||
|
||||
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.bindValue(":id_room", replay.game_info().room_id());
|
||||
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(":room_name", room->getName());
|
||||
query1.bindValue(":id_game", replay.game_info().game_id());
|
||||
query1.bindValue(":descr", QString::fromStdString(replay.game_info().description()));
|
||||
query1.bindValue(":creator_name", QString::fromStdString(replay.game_info().creator_info().name()));
|
||||
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(":seconds", secondsElapsed);
|
||||
query1.bindValue(":replay", replayBlob);
|
||||
if (!execSqlQuery(query1))
|
||||
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;
|
||||
query2.prepare("insert into " + dbPrefix + "_games_players (id_game, player_name) values (:id_game, :player_name)");
|
||||
QVariantList gameIds, playerNames;
|
||||
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(":id_game", gameIds1);
|
||||
query2.bindValue(":player_name", playerNames);
|
||||
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)
|
||||
|
|
|
@ -71,7 +71,7 @@ public:
|
|||
bool getThreaded() const { return threaded; }
|
||||
QString getDbPrefix() const { return dbPrefix; }
|
||||
void updateLoginMessage();
|
||||
ServerInfo_User getUserData(const QString &name);
|
||||
ServerInfo_User getUserData(const QString &name, bool withId = false);
|
||||
int getUsersWithAddress(const QHostAddress &address) const;
|
||||
QList<ServerSocketInterface *> getUsersWithAddressAsList(const QHostAddress &address) const;
|
||||
QMap<QString, ServerInfo_User> getBuddyList(const QString &name);
|
||||
|
@ -82,7 +82,7 @@ public:
|
|||
void incTxBytes(quint64 num);
|
||||
void incRxBytes(quint64 num);
|
||||
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:
|
||||
int startSession(const QString &userName, const QString &address);
|
||||
void endSession(int sessionId);
|
||||
|
@ -106,7 +106,7 @@ private:
|
|||
quint64 txBytes, rxBytes;
|
||||
int maxGameInactivityTime, maxPlayerInactivityTime;
|
||||
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;
|
||||
int shutdownMinutes;
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "pb/command_deck_new_dir.pb.h"
|
||||
#include "pb/command_deck_del_dir.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_server_message.pb.h"
|
||||
#include "pb/event_server_identification.pb.h"
|
||||
|
@ -42,6 +44,9 @@
|
|||
#include "pb/response_deck_list.pb.h"
|
||||
#include "pb/response_deck_download.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_deckstorage.pb.h"
|
||||
|
||||
|
@ -175,7 +180,7 @@ Response::ResponseCode ServerSocketInterface::cmdAddToList(const Command_AddToLi
|
|||
if (servatrice->isInIgnoreList(QString::fromStdString(userInfo->name()), user))
|
||||
return Response::RespContextError;
|
||||
|
||||
int id1 = servatrice->getUserIdInDB(QString::fromStdString(userInfo->name()));
|
||||
int id1 = userInfo->id();
|
||||
int id2 = servatrice->getUserIdInDB(user);
|
||||
if (id2 < 0)
|
||||
return Response::RespNameNotFound;
|
||||
|
@ -216,7 +221,7 @@ Response::ResponseCode ServerSocketInterface::cmdRemoveFromList(const Command_Re
|
|||
if (!servatrice->isInIgnoreList(QString::fromStdString(userInfo->name()), user))
|
||||
return Response::RespContextError;
|
||||
|
||||
int id1 = servatrice->getUserIdInDB(QString::fromStdString(userInfo->name()));
|
||||
int id1 = userInfo->id();
|
||||
int id2 = servatrice->getUserIdInDB(user);
|
||||
if (id2 < 0)
|
||||
return Response::RespNameNotFound;
|
||||
|
@ -485,6 +490,77 @@ Response::ResponseCode ServerSocketInterface::cmdDeckDownload(const Command_Deck
|
|||
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.
|
||||
// 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.bindValue(":user_name", userName);
|
||||
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(":reason", QString::fromStdString(cmd.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);
|
||||
DeckList *getDeckFromDatabase(int deckId);
|
||||
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 cmdShutdownServer(const Command_ShutdownServer &cmd, ResponseContainer &rc);
|
||||
Response::ResponseCode cmdUpdateServerMessage(const Command_UpdateServerMessage &cmd, ResponseContainer &rc);
|
||||
|
|
Loading…
Reference in a new issue