Replays split up, one for each subgame

This commit is contained in:
Max-Wilhelm Bruker 2012-03-02 20:45:04 +01:00
parent 4dc712286f
commit 8481e61e8f
15 changed files with 278 additions and 119 deletions

View file

@ -9,10 +9,24 @@
#include "pb/response_replay_list.pb.h"
#include "pb/serverinfo_replay.pb.h"
RemoteReplayList_TreeModel::MatchNode::MatchNode(const ServerInfo_ReplayMatch &_matchInfo)
: RemoteReplayList_TreeModel::Node(QString::fromStdString(_matchInfo.game_name())), matchInfo(_matchInfo)
{
for (int i = 0; i < matchInfo.replay_list_size(); ++i)
append(new ReplayNode(matchInfo.replay_list(i)));
}
RemoteReplayList_TreeModel::MatchNode::~MatchNode()
{
for (int i = 0; i < size(); ++i)
delete at(i);
}
RemoteReplayList_TreeModel::RemoteReplayList_TreeModel(AbstractClient *_client, QObject *parent)
: QAbstractItemModel(parent), client(_client)
{
QFileIconProvider fip;
dirIcon = fip.icon(QFileIconProvider::Folder);
fileIcon = fip.icon(QFileIconProvider::File);
refreshTree();
@ -20,47 +34,74 @@ RemoteReplayList_TreeModel::RemoteReplayList_TreeModel(AbstractClient *_client,
RemoteReplayList_TreeModel::~RemoteReplayList_TreeModel()
{
clearTree();
}
int RemoteReplayList_TreeModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : replays.size();
if (!parent.isValid())
return replayMatches.size();
MatchNode *matchNode = dynamic_cast<MatchNode *>(static_cast<Node *>(parent.internalPointer()));
if (matchNode)
return matchNode->size();
else
return 0;
}
int RemoteReplayList_TreeModel::columnCount(const QModelIndex &/*parent*/) const
{
return 6;
return 5;
}
QVariant RemoteReplayList_TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.column() > 5)
if (index.column() > 4)
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(", ");
ReplayNode *replayNode = dynamic_cast<ReplayNode *>(static_cast<Node *>(index.internalPointer()));
if (replayNode) {
const ServerInfo_Replay &replayInfo = replayNode->getReplayInfo();
switch (role) {
case Qt::TextAlignmentRole:
return index.column() == 0 ? Qt::AlignRight : Qt::AlignLeft;
case Qt::DisplayRole: {
switch (index.column()) {
case 0: return replayInfo.replay_id();
case 1: return QString::fromStdString(replayInfo.replay_name());
case 4: return replayInfo.duration();
default: return QVariant();
}
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();
}
} else {
MatchNode *matchNode = dynamic_cast<MatchNode *>(static_cast<Node *>(index.internalPointer()));
const ServerInfo_ReplayMatch &matchInfo = matchNode->getMatchInfo();
switch (role) {
case Qt::TextAlignmentRole:
return index.column() == 0 ? Qt::AlignRight : Qt::AlignLeft;
case Qt::DisplayRole: {
switch (index.column()) {
case 0: return matchInfo.game_id();
case 1: return QString::fromStdString(matchInfo.game_name());
case 2: {
QStringList playerList;
for (int i = 0; i < matchInfo.player_names_size(); ++i)
playerList.append(QString::fromStdString(matchInfo.player_names(i)));
return playerList.join(", ");
}
case 3: return QDateTime::fromTime_t(matchInfo.time_started());
case 4: return matchInfo.length();
default: return QVariant();
}
}
case Qt::DecorationRole:
return index.column() == 0 ? dirIcon : QVariant();
}
case Qt::DecorationRole:
return index.column() == 0 ? fileIcon : QVariant();
}
return QVariant();
}
@ -74,12 +115,11 @@ QVariant RemoteReplayList_TreeModel::headerData(int section, Qt::Orientation ori
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)");
case 0: return tr("ID");
case 1: return tr("Name");
case 2: return tr("Players");
case 3: return tr("Time started");
case 4: return tr("Duration (sec)");
default: return QVariant();
}
}
@ -91,13 +131,28 @@ QModelIndex RemoteReplayList_TreeModel::index(int row, int column, const QModelI
{
if (!hasIndex(row, column, parent))
return QModelIndex();
return createIndex(row, column, (void *) &(replays[row]));
MatchNode *matchNode = dynamic_cast<MatchNode *>(static_cast<Node *>(parent.internalPointer()));
if (matchNode) {
if (row >= matchNode->size())
return QModelIndex();
return createIndex(row, column, (void *) matchNode->at(row));
} else {
if (row >= replayMatches.size())
return QModelIndex();
return createIndex(row, column, (void *) replayMatches[row]);
}
}
QModelIndex RemoteReplayList_TreeModel::parent(const QModelIndex &ind) const
{
return QModelIndex();
MatchNode const *matchNode = dynamic_cast<MatchNode *>(static_cast<Node *>(ind.internalPointer()));
if (matchNode)
return QModelIndex();
else {
ReplayNode *replayNode = dynamic_cast<ReplayNode *>(static_cast<Node *>(ind.internalPointer()));
return createIndex(replayNode->getParent()->indexOf(replayNode), 0, replayNode);
}
}
Qt::ItemFlags RemoteReplayList_TreeModel::flags(const QModelIndex &index) const
@ -108,12 +163,33 @@ Qt::ItemFlags RemoteReplayList_TreeModel::flags(const QModelIndex &index) const
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
ServerInfo_Replay const* RemoteReplayList_TreeModel::getNode(const QModelIndex &index) const
ServerInfo_Replay const* RemoteReplayList_TreeModel::getReplay(const QModelIndex &index) const
{
if (!index.isValid())
return 0;
return &(replays[index.row()]);
ReplayNode *node = dynamic_cast<ReplayNode *>(static_cast<Node *>(index.internalPointer()));
if (!node)
return 0;
return &node->getReplayInfo();
}
ServerInfo_ReplayMatch const* RemoteReplayList_TreeModel::getReplayMatch(const QModelIndex &index) const
{
if (!index.isValid())
return 0;
MatchNode *node = dynamic_cast<MatchNode *>(static_cast<Node *>(index.internalPointer()));
if (!node)
return 0;
return &node->getMatchInfo();
}
void RemoteReplayList_TreeModel::clearTree()
{
for (int i = 0; i < replayMatches.size(); ++i)
delete replayMatches[i];
replayMatches.clear();
}
void RemoteReplayList_TreeModel::refreshTree()
@ -129,10 +205,10 @@ void RemoteReplayList_TreeModel::replayListFinished(const Response &r)
const Response_ReplayList &resp = r.GetExtension(Response_ReplayList::ext);
beginResetModel();
replays.clear();
clearTree();
for (int i = 0; i < resp.replay_list_size(); ++i)
replays.append(resp.replay_list(i));
for (int i = 0; i < resp.match_list_size(); ++i)
replayMatches.append(new MatchNode(resp.match_list(i)));
endResetModel();
emit treeRefreshed();
@ -156,12 +232,7 @@ RemoteReplayList_TreeWidget::RemoteReplayList_TreeWidget(AbstractClient *_client
header()->setSortIndicator(0, Qt::AscendingOrder);
}
ServerInfo_Replay const *RemoteReplayList_TreeWidget::getNode(const QModelIndex &ind) const
ServerInfo_Replay const *RemoteReplayList_TreeWidget::getCurrentReplay() const
{
return treeModel->getNode(proxyModel->mapToSource(ind));
}
ServerInfo_Replay const *RemoteReplayList_TreeWidget::getCurrentItem() const
{
return getNode(selectionModel()->currentIndex());
return treeModel->getReplay(proxyModel->mapToSource(selectionModel()->currentIndex()));
}

View file

@ -5,6 +5,7 @@
#include <QDateTime>
#include <QTreeView>
#include "pb/serverinfo_replay.pb.h"
#include "pb/serverinfo_replay_match.pb.h"
class Response;
class AbstractClient;
@ -13,10 +14,42 @@ class QSortFilterProxyModel;
class RemoteReplayList_TreeModel : public QAbstractItemModel {
Q_OBJECT
private:
AbstractClient *client;
QList<ServerInfo_Replay> replays;
class MatchNode;
class ReplayNode;
class Node {
protected:
QString name;
public:
Node(const QString &_name)
: name(_name) { }
virtual ~Node() { };
QString getName() const { return name; }
};
class MatchNode : public Node, public QList<ReplayNode *> {
private:
ServerInfo_ReplayMatch matchInfo;
public:
MatchNode(const ServerInfo_ReplayMatch &_matchInfo);
~MatchNode();
void clearTree();
const ServerInfo_ReplayMatch &getMatchInfo() { return matchInfo; }
};
class ReplayNode : public Node {
private:
MatchNode *parent;
ServerInfo_Replay replayInfo;
public:
ReplayNode(const ServerInfo_Replay &_replayInfo, MatchNode *_parent = 0)
: Node(QString::fromStdString(_replayInfo.replay_name())), parent(_parent), replayInfo(_replayInfo) { }
MatchNode *getParent() const { return parent; }
const ServerInfo_Replay &getReplayInfo() { return replayInfo; }
};
QIcon fileIcon;
AbstractClient *client;
QList<MatchNode *> replayMatches;
QIcon dirIcon, fileIcon;
void clearTree();
signals:
void treeRefreshed();
private slots:
@ -32,7 +65,8 @@ public:
QModelIndex parent(const QModelIndex &index) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
void refreshTree();
ServerInfo_Replay const *getNode(const QModelIndex &index) const;
ServerInfo_Replay const* getReplay(const QModelIndex &index) const;
ServerInfo_ReplayMatch const* getReplayMatch(const QModelIndex &index) const;
};
class RemoteReplayList_TreeWidget : public QTreeView {
@ -42,7 +76,8 @@ private:
ServerInfo_Replay const *getNode(const QModelIndex &ind) const;
public:
RemoteReplayList_TreeWidget(AbstractClient *_client, QWidget *parent = 0);
ServerInfo_Replay const *getCurrentItem() const;
ServerInfo_Replay const *getCurrentReplay() const;
ServerInfo_ReplayMatch const *getCurrentReplayMatch() const;
void refreshTree();
};

View file

@ -198,7 +198,7 @@ void DeckViewContainer::setDeck(DeckList *deck)
deckView->setDeck(deck);
readyStartButton->setEnabled(true);
}
#include <QDebug>
TabGame::TabGame(GameReplay *_replay)
: Tab(0),
hostId(-1),

View file

@ -123,12 +123,12 @@ void TabReplays::actOpenLocalReplay()
void TabReplays::actOpenRemoteReplay()
{
ServerInfo_Replay const *curRight = serverDirView->getCurrentItem();
ServerInfo_Replay const *curRight = serverDirView->getCurrentReplay();
if (!curRight)
return;
Command_ReplayDownload cmd;
cmd.set_game_id(curRight->game_id());
cmd.set_replay_id(curRight->replay_id());
PendingCommand *pend = client->prepareSessionCommand(cmd);
connect(pend, SIGNAL(finished(const Response &)), this, SLOT(openRemoteReplayFinished(const Response &)));
@ -156,13 +156,13 @@ void TabReplays::actDownload()
filePath = localDirModel->filePath(curLeft);
}
ServerInfo_Replay const *curRight = serverDirView->getCurrentItem();
ServerInfo_Replay const *curRight = serverDirView->getCurrentReplay();
if (!curRight)
return;
filePath += QString("/game_%1.cor").arg(curRight->game_id());
filePath += QString("/replay_%1.cor").arg(curRight->replay_id());
Command_ReplayDownload cmd;
cmd.set_game_id(curRight->game_id());
cmd.set_replay_id(curRight->replay_id());
PendingCommand *pend = client->prepareSessionCommand(cmd);
pend->setExtraData(filePath);

View file

@ -126,6 +126,7 @@ SET(PROTO_FILES
serverinfo_playerproperties.proto
serverinfo_player.proto
serverinfo_replay.proto
serverinfo_replay_match.proto
serverinfo_room.proto
serverinfo_user.proto
serverinfo_zone.proto

View file

@ -4,5 +4,5 @@ message Command_ReplayDownload {
extend SessionCommand {
optional Command_ReplayDownload ext = 1101;
}
optional sint32 game_id = 1 [default = -1];
optional sint32 replay_id = 1 [default = -1];
}

View file

@ -4,4 +4,5 @@ import "game_event_container.proto";
message GameReplay {
optional ServerInfo_Game game_info = 1;
repeated GameEventContainer event_list = 2;
optional uint32 duration_seconds = 3;
}

View file

@ -1,9 +1,9 @@
import "response.proto";
import "serverinfo_replay.proto";
import "serverinfo_replay_match.proto";
message Response_ReplayList {
extend Response {
optional Response_ReplayList ext = 1100;
}
repeated ServerInfo_Replay replay_list = 1;
repeated ServerInfo_ReplayMatch match_list = 1;
}

View file

@ -1,9 +1,5 @@
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;
optional sint32 replay_id = 1 [default = -1];
optional string replay_name = 2;
optional uint32 duration = 3;
}

View file

@ -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 QSet<QString> &allPlayersEver, const QSet<QString> &allSpectatorsEver, const GameReplay &replay) { }
virtual void storeGameInformation(int secondsElapsed, const QSet<QString> &allPlayersEver, const QSet<QString> &allSpectatorsEver, const QList<GameReplay *> &replays) { }
protected:
void prepareDestroy();
QList<Server_ProtocolHandler *> clients;

View file

@ -45,14 +45,15 @@
#include <QDebug>
Server_Game::Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, const QList<int> &_gameTypes, bool _onlyBuddies, bool _onlyRegistered, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server_Room *_room)
: 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), startTimeOfThisGame(0), secondsElapsed(0), firstGameStarted(false), startTime(QDateTime::currentDateTime()), gameMutex(QMutex::Recursive)
{
replay = new GameReplay;
currentReplay = new GameReplay;
connect(this, SIGNAL(sigStartGameIfReady()), this, SLOT(doStartGameIfReady()), Qt::QueuedConnection);
addPlayer(_creator, false, false);
replay->mutable_game_info()->CopyFrom(getInfo());
currentReplay->mutable_game_info()->CopyFrom(getInfo());
if (room->getServer()->getGameShouldPing()) {
pingClock = new QTimer(this);
@ -80,8 +81,12 @@ Server_Game::~Server_Game()
gameMutex.unlock();
room->roomMutex.unlock();
room->getServer()->storeGameInformation(secondsElapsed, allPlayersEver, allSpectatorsEver, *replay);
delete replay;
currentReplay->set_duration_seconds(secondsElapsed - startTimeOfThisGame);
replayList.append(currentReplay);
room->getServer()->storeGameInformation(secondsElapsed, allPlayersEver, allSpectatorsEver, replayList);
for (int i = 0; i < replayList.size(); ++i)
delete replayList[i];
qDebug() << "Server_Game destructor: gameId=" << gameId;
}
@ -176,9 +181,9 @@ void Server_Game::sendGameStateToPlayers()
omniscientEvent.add_player_list()->CopyFrom(omniscientGameStateIterator.next());
GameEventContainer *replayCont = prepareGameEvent(omniscientEvent, -1);
replayCont->set_seconds_elapsed(secondsElapsed);
replayCont->set_seconds_elapsed(secondsElapsed - startTimeOfThisGame);
replayCont->clear_game_id();
replay->add_event_list()->CopyFrom(*replayCont);
currentReplay->add_event_list()->CopyFrom(*replayCont);
delete replayCont;
// If spectators are not omniscient, we need an additional getGameState call, otherwise we can use the data we used for the replay.
@ -237,6 +242,27 @@ void Server_Game::doStartGameIfReady()
player->setReadyStart(false);
}
if (firstGameStarted) {
currentReplay->set_duration_seconds(secondsElapsed - startTimeOfThisGame);
replayList.append(currentReplay);
currentReplay = new GameReplay;
currentReplay->mutable_game_info()->CopyFrom(getInfo());
Event_GameStateChanged omniscientEvent;
QListIterator<ServerInfo_Player> omniscientGameStateIterator(getGameState(0, true, true));
while (omniscientGameStateIterator.hasNext())
omniscientEvent.add_player_list()->CopyFrom(omniscientGameStateIterator.next());
GameEventContainer *replayCont = prepareGameEvent(omniscientEvent, -1);
replayCont->set_seconds_elapsed(0);
replayCont->clear_game_id();
currentReplay->add_event_list()->CopyFrom(*replayCont);
delete replayCont;
startTimeOfThisGame = secondsElapsed;
} else
firstGameStarted = true;
sendGameStateToPlayers();
activePlayer = -1;
@ -624,9 +650,9 @@ void Server_Game::sendGameEventContainer(GameEventContainer *cont, GameEventStor
p->sendGameEvent(*cont);
}
if (recipients.testFlag(GameEventStorageItem::SendToPrivate)) {
cont->set_seconds_elapsed(secondsElapsed);
cont->set_seconds_elapsed(secondsElapsed - startTimeOfThisGame);
cont->clear_game_id();
replay->add_event_list()->CopyFrom(*cont);
currentReplay->add_event_list()->CopyFrom(*cont);
}
delete cont;

View file

@ -59,10 +59,12 @@ private:
bool spectatorsCanTalk;
bool spectatorsSeeEverything;
int inactivityCounter;
int secondsElapsed;
int startTimeOfThisGame, secondsElapsed;
bool firstGameStarted;
QDateTime startTime;
QTimer *pingClock;
GameReplay *replay;
QList<GameReplay *> replayList;
GameReplay *currentReplay;
signals:
void sigStartGameIfReady();
private slots:

View file

@ -538,42 +538,21 @@ void Servatrice::statusUpdate()
execSqlQuery(query);
}
void Servatrice::storeGameInformation(int secondsElapsed, const QSet<QString> &allPlayersEver, const QSet<QString> &allSpectatorsEver, const GameReplay &replay)
void Servatrice::storeGameInformation(int secondsElapsed, const QSet<QString> &allPlayersEver, const QSet<QString> &allSpectatorsEver, const QList<GameReplay *> &replayList)
{
Server_Room *room = rooms.value(replay.game_info().room_id());
const ServerInfo_Game &gameInfo = replayList.first()->game_info();
Server_Room *room = rooms.value(gameInfo.room_id());
const QStringList &allGameTypes = room->getGameTypes();
QStringList gameTypes;
for (int i = replay.game_info().game_types_size() - 1; i >= 0; --i)
gameTypes.append(allGameTypes[replay.game_info().game_types(i)]);
QByteArray replayBlob;
const unsigned int size = replay.ByteSize();
replayBlob.resize(size);
replay.SerializeToArray(replayBlob.data(), size);
QMutexLocker locker(&dbMutex);
if (!checkSql())
return;
QSqlQuery query1;
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(":player_count", replay.game_info().max_players());
query1.bindValue(":seconds", secondsElapsed);
query1.bindValue(":replay", replayBlob);
if (!execSqlQuery(query1))
return;
for (int i = gameInfo.game_types_size() - 1; i >= 0; --i)
gameTypes.append(allGameTypes[gameInfo.game_types(i)]);
QVariantList gameIds1, playerNames, gameIds2, userIds, replayNames;
QSetIterator<QString> playerIterator(allPlayersEver);
while (playerIterator.hasNext()) {
gameIds1.append(replay.game_info().game_id());
gameIds1.append(gameInfo.game_id());
playerNames.append(playerIterator.next());
}
QSet<QString> allUsersInGame = allPlayersEver + allSpectatorsEver;
@ -582,17 +561,53 @@ void Servatrice::storeGameInformation(int secondsElapsed, const QSet<QString> &a
int id = getUserIdInDB(allUsersIterator.next());
if (id == -1)
continue;
gameIds2.append(replay.game_info().game_id());
gameIds2.append(gameInfo.game_id());
userIds.append(id);
replayNames.append(QString::fromStdString(replay.game_info().description()));
replayNames.append(QString::fromStdString(gameInfo.description()));
}
QVariantList replayGameIds, replayDurations, replayBlobs;
for (int i = 0; i < replayList.size(); ++i) {
QByteArray blob;
const unsigned int size = replayList[i]->ByteSize();
blob.resize(size);
replayList[i]->SerializeToArray(blob.data(), size);
replayGameIds.append(gameInfo.game_id());
replayDurations.append(replayList[i]->duration_seconds());
replayBlobs.append(blob);
}
QMutexLocker locker(&dbMutex);
if (!checkSql())
return;
QSqlQuery query1;
query1.prepare("insert into " + dbPrefix + "_games (room_name, id, descr, creator_name, password, game_types, player_count, time_started, time_finished) values (:id_room, :id_game, :descr, :creator_name, :password, :game_types, :player_count, date_sub(now(), interval :seconds second), now())");
query1.bindValue(":room_name", room->getName());
query1.bindValue(":id_game", gameInfo.game_id());
query1.bindValue(":descr", QString::fromStdString(gameInfo.description()));
query1.bindValue(":creator_name", QString::fromStdString(gameInfo.creator_info().name()));
query1.bindValue(":password", gameInfo.with_password() ? 1 : 0);
query1.bindValue(":game_types", gameTypes.isEmpty() ? QString("") : gameTypes.join(", "));
query1.bindValue(":player_count", gameInfo.max_players());
query1.bindValue(":seconds", secondsElapsed);
if (!execSqlQuery(query1))
return;
QSqlQuery query2;
query2.prepare("insert into " + dbPrefix + "_games_players (id_game, player_name) values (:id_game, :player_name)");
query2.bindValue(":id_game", gameIds1);
query2.bindValue(":player_name", playerNames);
query2.execBatch();
QSqlQuery replayQuery1;
replayQuery1.prepare("insert into " + dbPrefix + "_replays (id_game, duration, replay) values (:id_game, :duration, :replay)");
replayQuery1.bindValue(":id_game", replayGameIds);
replayQuery1.bindValue(":duration", replayDurations);
replayQuery1.bindValue(":replay", replayBlobs);
replayQuery1.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);

View file

@ -82,7 +82,7 @@ public:
void incTxBytes(quint64 num);
void incRxBytes(quint64 num);
int getUserIdInDB(const QString &name);
void storeGameInformation(int secondsElapsed, const QSet<QString> &allPlayersEver, const QSet<QString> &allSpectatorsEver, const GameReplay &replay);
void storeGameInformation(int secondsElapsed, const QSet<QString> &allPlayersEver, const QSet<QString> &allSpectatorsEver, const QList<GameReplay *> &replays);
protected:
int startSession(const QString &userName, const QString &address);
void endSession(int sessionId);

View file

@ -503,23 +503,35 @@ Response::ResponseCode ServerSocketInterface::cmdReplayList(const Command_Replay
query1.bindValue(":id_player", userInfo->id());
servatrice->execSqlQuery(query1);
while (query1.next()) {
ServerInfo_Replay *replayInfo = re->add_replay_list();
ServerInfo_ReplayMatch *matchInfo = re->add_match_list();
const int gameId = query1.value(0).toInt();
replayInfo->set_game_id(gameId);
replayInfo->set_room_name(query1.value(2).toString().toStdString());
matchInfo->set_game_id(gameId);
matchInfo->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());
matchInfo->set_time_started(timeStarted);
matchInfo->set_length(timeFinished - timeStarted);
matchInfo->set_game_name(query1.value(5).toString().toStdString());
const QString replayName = query1.value(1).toString();
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());
matchInfo->add_player_names(query2.value(0).toString().toStdString());
QSqlQuery query3;
query3.prepare("select id, duration from " + servatrice->getDbPrefix() + "_replays where id_game = :id_game");
query3.bindValue(":id_game", gameId);
servatrice->execSqlQuery(query3);
while (query3.next()) {
ServerInfo_Replay *replayInfo = matchInfo->add_replay_list();
replayInfo->set_replay_id(query3.value(0).toInt());
replayInfo->set_replay_name(replayName.toStdString());
replayInfo->set_duration(query3.value(1).toInt());
}
}
servatrice->dbMutex.unlock();
@ -535,8 +547,8 @@ Response::ResponseCode ServerSocketInterface::cmdReplayDownload(const Command_Re
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.prepare("select 1 from " + servatrice->getDbPrefix() + "_replays_access a left join " + servatrice->getDbPrefix() + "_replays b on a.id_game = b.id_game where b.id = :id_replay and a.id_player = :id_player");
query1.bindValue(":id_replay", cmd.replay_id());
query1.bindValue(":id_player", userInfo->id());
if (!servatrice->execSqlQuery(query1))
return Response::RespInternalError;
@ -544,8 +556,8 @@ Response::ResponseCode ServerSocketInterface::cmdReplayDownload(const Command_Re
return Response::RespAccessDenied;
QSqlQuery query2;
query2.prepare("select replay from " + servatrice->getDbPrefix() + "_games where id = :id_game");
query2.bindValue(":id_game", cmd.game_id());
query2.prepare("select replay from " + servatrice->getDbPrefix() + "_replays where id = :id_replay");
query2.bindValue(":id_replay", cmd.replay_id());
if (!servatrice->execSqlQuery(query2))
return Response::RespInternalError;
if (!query2.next())