server-side replay support
This commit is contained in:
parent
7cec442694
commit
d50d179b2f
13 changed files with 177 additions and 89 deletions
|
@ -11,23 +11,10 @@ class LocalServer : public Server
|
||||||
public:
|
public:
|
||||||
LocalServer(QObject *parent = 0);
|
LocalServer(QObject *parent = 0);
|
||||||
~LocalServer();
|
~LocalServer();
|
||||||
AuthenticationResult checkUserPassword(Server_ProtocolHandler * /*handler*/, const QString & /*user*/, const QString & /*password*/, QString & /*reasonStr*/) { return UnknownUser; }
|
|
||||||
QString getLoginMessage() const { return QString(); }
|
|
||||||
bool getGameShouldPing() const { return false; }
|
|
||||||
int getMaxGameInactivityTime() const { return 9999999; }
|
|
||||||
int getMaxPlayerInactivityTime() const { return 9999999; }
|
|
||||||
bool getThreaded() const { return false; }
|
|
||||||
|
|
||||||
LocalServerInterface *newConnection();
|
LocalServerInterface *newConnection();
|
||||||
protected:
|
protected:
|
||||||
int startSession(const QString & /*userName*/, const QString & /*address*/) { return -1; }
|
|
||||||
void endSession(int /*sessionId*/) { }
|
|
||||||
bool userExists(const QString & /*name*/) { return false; }
|
|
||||||
ServerInfo_User getUserData(const QString &name);
|
ServerInfo_User getUserData(const QString &name);
|
||||||
QMap<QString, ServerInfo_User> getBuddyList(const QString & /*name*/) { return QMap<QString, ServerInfo_User>(); }
|
|
||||||
QMap<QString, ServerInfo_User> getIgnoreList(const QString & /*name*/) { return QMap<QString, ServerInfo_User>(); }
|
|
||||||
bool isInBuddyList(const QString & /*whoseList*/, const QString & /*who*/) { return false; }
|
|
||||||
bool isInIgnoreList(const QString & /*whoseList*/, const QString & /*who*/) { return false; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -95,6 +95,7 @@ SET(PROTO_FILES
|
||||||
game_event_container.proto
|
game_event_container.proto
|
||||||
game_event_context.proto
|
game_event_context.proto
|
||||||
game_event.proto
|
game_event.proto
|
||||||
|
game_replay.proto
|
||||||
moderator_commands.proto
|
moderator_commands.proto
|
||||||
move_card_to_zone.proto
|
move_card_to_zone.proto
|
||||||
response_deck_download.proto
|
response_deck_download.proto
|
||||||
|
|
|
@ -5,4 +5,5 @@ message GameEventContainer {
|
||||||
optional uint32 game_id = 1;
|
optional uint32 game_id = 1;
|
||||||
repeated GameEvent event_list = 2;
|
repeated GameEvent event_list = 2;
|
||||||
optional GameEventContext context = 3;
|
optional GameEventContext context = 3;
|
||||||
|
optional uint32 seconds_elapsed = 4;
|
||||||
}
|
}
|
||||||
|
|
7
common/pb/game_replay.proto
Normal file
7
common/pb/game_replay.proto
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import "serverinfo_game.proto";
|
||||||
|
import "game_event_container.proto";
|
||||||
|
|
||||||
|
message GameReplay {
|
||||||
|
optional ServerInfo_Game game_info = 1;
|
||||||
|
repeated GameEventContainer event_list = 2;
|
||||||
|
}
|
|
@ -15,4 +15,5 @@ message ServerInfo_Game {
|
||||||
optional bool spectators_allowed = 12;
|
optional bool spectators_allowed = 12;
|
||||||
optional bool spectators_need_password = 13;
|
optional bool spectators_need_password = 13;
|
||||||
optional uint32 spectators_count = 14;
|
optional uint32 spectators_count = 14;
|
||||||
|
optional uint32 start_time = 15;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
class Server_Game;
|
class Server_Game;
|
||||||
class Server_Room;
|
class Server_Room;
|
||||||
class Server_ProtocolHandler;
|
class Server_ProtocolHandler;
|
||||||
|
class GameReplay;
|
||||||
|
|
||||||
enum AuthenticationResult { NotLoggedIn = 0, PasswordRight = 1, UnknownUser = 2, WouldOverwriteOldSession = 3, UserIsBanned = 4 };
|
enum AuthenticationResult { NotLoggedIn = 0, PasswordRight = 1, UnknownUser = 2, WouldOverwriteOldSession = 3, UserIsBanned = 4 };
|
||||||
|
|
||||||
|
@ -31,31 +32,33 @@ public:
|
||||||
const QMap<QString, Server_ProtocolHandler *> &getUsers() const { return users; }
|
const QMap<QString, Server_ProtocolHandler *> &getUsers() const { return users; }
|
||||||
void addClient(Server_ProtocolHandler *player);
|
void addClient(Server_ProtocolHandler *player);
|
||||||
void removeClient(Server_ProtocolHandler *player);
|
void removeClient(Server_ProtocolHandler *player);
|
||||||
virtual QString getLoginMessage() const = 0;
|
virtual QString getLoginMessage() const { return QString(); }
|
||||||
|
|
||||||
virtual bool getGameShouldPing() const = 0;
|
virtual bool getGameShouldPing() const { return false; }
|
||||||
virtual int getMaxGameInactivityTime() const = 0;
|
virtual int getMaxGameInactivityTime() const { return 9999999; }
|
||||||
virtual int getMaxPlayerInactivityTime() const = 0;
|
virtual int getMaxPlayerInactivityTime() const { return 9999999; }
|
||||||
virtual int getMessageCountingInterval() const { return 0; }
|
virtual int getMessageCountingInterval() const { return 0; }
|
||||||
virtual int getMaxMessageCountPerInterval() const { return 0; }
|
virtual int getMaxMessageCountPerInterval() const { return 0; }
|
||||||
virtual int getMaxMessageSizePerInterval() const { return 0; }
|
virtual int getMaxMessageSizePerInterval() const { return 0; }
|
||||||
virtual int getMaxGamesPerUser() const { return 0; }
|
virtual int getMaxGamesPerUser() const { return 0; }
|
||||||
virtual bool getThreaded() const = 0;
|
virtual bool getThreaded() const { return false; }
|
||||||
|
|
||||||
virtual QMap<QString, ServerInfo_User> getBuddyList(const QString &name) = 0;
|
virtual QMap<QString, ServerInfo_User> getBuddyList(const QString &name) { return QMap<QString, ServerInfo_User>(); }
|
||||||
virtual QMap<QString, ServerInfo_User> getIgnoreList(const QString &name) = 0;
|
virtual QMap<QString, ServerInfo_User> getIgnoreList(const QString &name) { return QMap<QString, ServerInfo_User>(); }
|
||||||
virtual bool isInBuddyList(const QString &whoseList, const QString &who) = 0;
|
virtual bool isInBuddyList(const QString &whoseList, const QString &who) { return false; }
|
||||||
virtual bool isInIgnoreList(const QString &whoseList, const QString &who) = 0;
|
virtual bool isInIgnoreList(const QString &whoseList, const QString &who) { return false; }
|
||||||
|
|
||||||
|
virtual void storeGameInformation(int secondsElapsed, const QStringList &allPlayersEver, const GameReplay &replay) { }
|
||||||
protected:
|
protected:
|
||||||
void prepareDestroy();
|
void prepareDestroy();
|
||||||
QList<Server_ProtocolHandler *> clients;
|
QList<Server_ProtocolHandler *> clients;
|
||||||
QMap<QString, Server_ProtocolHandler *> users;
|
QMap<QString, Server_ProtocolHandler *> users;
|
||||||
QMap<int, Server_Room *> rooms;
|
QMap<int, Server_Room *> rooms;
|
||||||
|
|
||||||
virtual int startSession(const QString &userName, const QString &address) = 0;
|
virtual int startSession(const QString &userName, const QString &address) { return -1; }
|
||||||
virtual void endSession(int sessionId) = 0;
|
virtual void endSession(int sessionId) { }
|
||||||
virtual bool userExists(const QString &user) = 0;
|
virtual bool userExists(const QString &user) { return false; }
|
||||||
virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reason) = 0;
|
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) = 0;
|
||||||
int getUsersCount() const;
|
int getUsersCount() const;
|
||||||
int getGamesCount() const;
|
int getGamesCount() const;
|
||||||
|
|
|
@ -39,13 +39,17 @@
|
||||||
#include "pb/event_set_active_player.pb.h"
|
#include "pb/event_set_active_player.pb.h"
|
||||||
#include "pb/event_set_active_phase.pb.h"
|
#include "pb/event_set_active_phase.pb.h"
|
||||||
#include "pb/serverinfo_playerping.pb.h"
|
#include "pb/serverinfo_playerping.pb.h"
|
||||||
|
#include "pb/game_replay.pb.h"
|
||||||
#include <google/protobuf/descriptor.h>
|
#include <google/protobuf/descriptor.h>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QDebug>
|
#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)
|
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), 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->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);
|
||||||
|
@ -59,8 +63,8 @@ Server_Game::Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QS
|
||||||
|
|
||||||
Server_Game::~Server_Game()
|
Server_Game::~Server_Game()
|
||||||
{
|
{
|
||||||
QMutexLocker roomLocker(&room->roomMutex);
|
room->roomMutex.lock();
|
||||||
QMutexLocker locker(&gameMutex);
|
gameMutex.lock();
|
||||||
|
|
||||||
sendGameEventContainer(prepareGameEvent(Event_GameClosed(), -1));
|
sendGameEventContainer(prepareGameEvent(Event_GameClosed(), -1));
|
||||||
|
|
||||||
|
@ -72,6 +76,13 @@ Server_Game::~Server_Game()
|
||||||
room->removeGame(this);
|
room->removeGame(this);
|
||||||
delete creatorInfo;
|
delete creatorInfo;
|
||||||
creatorInfo = 0;
|
creatorInfo = 0;
|
||||||
|
|
||||||
|
gameMutex.unlock();
|
||||||
|
room->roomMutex.unlock();
|
||||||
|
|
||||||
|
room->getServer()->storeGameInformation(secondsElapsed, allPlayersEver.toList(), *replay);
|
||||||
|
delete replay;
|
||||||
|
|
||||||
qDebug() << "Server_Game destructor: gameId=" << gameId;
|
qDebug() << "Server_Game destructor: gameId=" << gameId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +157,59 @@ int Server_Game::getSpectatorCount() const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Server_Game::sendGameStateToPlayers()
|
||||||
|
{
|
||||||
|
// Prepare game state information that everyone can see
|
||||||
|
Event_GameStateChanged gameStateChangedEvent;
|
||||||
|
gameStateChangedEvent.set_seconds_elapsed(secondsElapsed);
|
||||||
|
if (gameStarted) {
|
||||||
|
gameStateChangedEvent.set_game_started(true);
|
||||||
|
gameStateChangedEvent.set_active_player_id(0);
|
||||||
|
gameStateChangedEvent.set_active_phase(0);
|
||||||
|
} else
|
||||||
|
gameStateChangedEvent.set_game_started(false);
|
||||||
|
|
||||||
|
// game state information for replay and omniscient spectators
|
||||||
|
Event_GameStateChanged omniscientEvent(gameStateChangedEvent);
|
||||||
|
QListIterator<ServerInfo_Player> omniscientGameStateIterator(getGameState(0, true));
|
||||||
|
while (omniscientGameStateIterator.hasNext())
|
||||||
|
omniscientEvent.add_player_list()->CopyFrom(omniscientGameStateIterator.next());
|
||||||
|
|
||||||
|
GameEventContainer *replayCont = prepareGameEvent(omniscientEvent, -1);
|
||||||
|
replayCont->set_seconds_elapsed(secondsElapsed);
|
||||||
|
replayCont->clear_game_id();
|
||||||
|
replay->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.
|
||||||
|
// All spectators are equal, so we don't need to make a getGameState call for each one.
|
||||||
|
Event_GameStateChanged spectatorEvent(spectatorsSeeEverything ? omniscientEvent : gameStateChangedEvent);
|
||||||
|
if (!spectatorsSeeEverything) {
|
||||||
|
QListIterator<ServerInfo_Player> spectatorGameStateIterator(getGameState(0, false));
|
||||||
|
while (spectatorGameStateIterator.hasNext())
|
||||||
|
spectatorEvent.add_player_list()->CopyFrom(spectatorGameStateIterator.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
// send game state info to clients according to their role in the game
|
||||||
|
QMapIterator<int, Server_Player *> playerIterator(players);
|
||||||
|
while (playerIterator.hasNext()) {
|
||||||
|
Server_Player *player = playerIterator.next().value();
|
||||||
|
GameEventContainer *gec;
|
||||||
|
if (player->getSpectator())
|
||||||
|
gec = prepareGameEvent(spectatorEvent, -1);
|
||||||
|
else {
|
||||||
|
Event_GameStateChanged event(gameStateChangedEvent);
|
||||||
|
QListIterator<ServerInfo_Player> gameStateIterator(getGameState(player));
|
||||||
|
while (gameStateIterator.hasNext())
|
||||||
|
event.add_player_list()->CopyFrom(gameStateIterator.next());
|
||||||
|
|
||||||
|
gec = prepareGameEvent(event, -1);
|
||||||
|
}
|
||||||
|
player->sendGameEvent(*gec);
|
||||||
|
delete gec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Server_Game::doStartGameIfReady()
|
void Server_Game::doStartGameIfReady()
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&gameMutex);
|
QMutexLocker locker(&gameMutex);
|
||||||
|
@ -172,37 +236,9 @@ void Server_Game::doStartGameIfReady()
|
||||||
player->setConceded(false);
|
player->setConceded(false);
|
||||||
player->setReadyStart(false);
|
player->setReadyStart(false);
|
||||||
}
|
}
|
||||||
playerIterator.toFront();
|
|
||||||
while (playerIterator.hasNext()) {
|
|
||||||
Server_Player *player = playerIterator.next().value();
|
|
||||||
Event_GameStateChanged event;
|
|
||||||
event.set_seconds_elapsed(secondsElapsed);
|
|
||||||
event.set_game_started(true);
|
|
||||||
event.set_active_player_id(0);
|
|
||||||
event.set_active_phase(0);
|
|
||||||
QListIterator<ServerInfo_Player> gameStateIterator(getGameState(player));
|
|
||||||
while (gameStateIterator.hasNext())
|
|
||||||
event.add_player_list()->CopyFrom(gameStateIterator.next());
|
|
||||||
|
|
||||||
player->sendGameEvent(prepareGameEvent(event, -1));
|
sendGameStateToPlayers();
|
||||||
}
|
|
||||||
|
|
||||||
/* QSqlQuery query;
|
|
||||||
query.prepare("insert into games (id, descr, password, time_started) values(:id, :descr, :password, now())");
|
|
||||||
query.bindValue(":id", gameId);
|
|
||||||
query.bindValue(":descr", description);
|
|
||||||
query.bindValue(":password", !password.isEmpty());
|
|
||||||
query.exec();
|
|
||||||
|
|
||||||
QMapIterator<int, Server_Player *> playerIterator2(players);
|
|
||||||
while (playerIterator2.hasNext()) {
|
|
||||||
Server_Player *player = playerIterator2.next().value();
|
|
||||||
query.prepare("insert into games_players (id_game, player) values(:id, :player)");
|
|
||||||
query.bindValue(":id", gameId);
|
|
||||||
query.bindValue(":player", player->getPlayerName());
|
|
||||||
query.exec();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
activePlayer = -1;
|
activePlayer = -1;
|
||||||
nextTurn();
|
nextTurn();
|
||||||
|
|
||||||
|
@ -237,18 +273,7 @@ void Server_Game::stopGameIfFinished()
|
||||||
p->setConceded(false);
|
p->setConceded(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
playerIterator.toFront();
|
sendGameStateToPlayers();
|
||||||
while (playerIterator.hasNext()) {
|
|
||||||
Server_Player *player = playerIterator.next().value();
|
|
||||||
Event_GameStateChanged event;
|
|
||||||
event.set_seconds_elapsed(secondsElapsed);
|
|
||||||
event.set_game_started(false);
|
|
||||||
QListIterator<ServerInfo_Player> gameStateIterator(getGameState(player));
|
|
||||||
while (gameStateIterator.hasNext())
|
|
||||||
event.add_player_list()->CopyFrom(gameStateIterator.next());
|
|
||||||
|
|
||||||
player->sendGameEvent(prepareGameEvent(event, -1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Response::ResponseCode Server_Game::checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions)
|
Response::ResponseCode Server_Game::checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions)
|
||||||
|
@ -296,9 +321,10 @@ Server_Player *Server_Game::addPlayer(Server_ProtocolHandler *handler, bool spec
|
||||||
newPlayer->moveToThread(thread());
|
newPlayer->moveToThread(thread());
|
||||||
|
|
||||||
Event_Join joinEvent;
|
Event_Join joinEvent;
|
||||||
joinEvent.mutable_player_properties()->CopyFrom(newPlayer->getProperties());
|
joinEvent.mutable_player_properties()->CopyFrom(newPlayer->getProperties(true));
|
||||||
sendGameEventContainer(prepareGameEvent(joinEvent, -1));
|
sendGameEventContainer(prepareGameEvent(joinEvent, -1));
|
||||||
|
|
||||||
|
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;
|
||||||
|
@ -410,7 +436,9 @@ bool Server_Game::kickPlayer(int playerId)
|
||||||
if (!playerToKick)
|
if (!playerToKick)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
playerToKick->sendGameEvent(prepareGameEvent(Event_Kicked(), -1));
|
GameEventContainer *gec = prepareGameEvent(Event_Kicked(), -1);
|
||||||
|
playerToKick->sendGameEvent(*gec);
|
||||||
|
delete gec;
|
||||||
|
|
||||||
removePlayer(playerToKick);
|
removePlayer(playerToKick);
|
||||||
|
|
||||||
|
@ -473,7 +501,7 @@ void Server_Game::nextTurn()
|
||||||
setActivePlayer(keys[listPos]);
|
setActivePlayer(keys[listPos]);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<ServerInfo_Player> Server_Game::getGameState(Server_Player *playerWhosAsking) const
|
QList<ServerInfo_Player> Server_Game::getGameState(Server_Player *playerWhosAsking, bool omniscient, bool withUserInfo) const
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&gameMutex);
|
QMutexLocker locker(&gameMutex);
|
||||||
|
|
||||||
|
@ -483,7 +511,7 @@ QList<ServerInfo_Player> Server_Game::getGameState(Server_Player *playerWhosAski
|
||||||
Server_Player *player = playerIterator.next().value();
|
Server_Player *player = playerIterator.next().value();
|
||||||
|
|
||||||
ServerInfo_Player playerInfo;
|
ServerInfo_Player playerInfo;
|
||||||
playerInfo.mutable_properties()->CopyFrom(player->getProperties());
|
playerInfo.mutable_properties()->CopyFrom(player->getProperties(withUserInfo));
|
||||||
if (player == playerWhosAsking)
|
if (player == playerWhosAsking)
|
||||||
if (player->getDeck())
|
if (player->getDeck())
|
||||||
playerInfo.set_deck_list(player->getDeck()->writeToString_Native().toStdString());
|
playerInfo.set_deck_list(player->getDeck()->writeToString_Native().toStdString());
|
||||||
|
@ -528,7 +556,7 @@ QList<ServerInfo_Player> Server_Game::getGameState(Server_Player *playerWhosAski
|
||||||
zoneInfo->set_with_coords(zone->hasCoords());
|
zoneInfo->set_with_coords(zone->hasCoords());
|
||||||
zoneInfo->set_card_count(zone->cards.size());
|
zoneInfo->set_card_count(zone->cards.size());
|
||||||
if (
|
if (
|
||||||
(((playerWhosAsking == player) || (playerWhosAsking->getSpectator() && spectatorsSeeEverything)) && (zone->getType() != ServerInfo_Zone::HiddenZone))
|
(((playerWhosAsking == player) || omniscient) && (zone->getType() != ServerInfo_Zone::HiddenZone))
|
||||||
|| ((playerWhosAsking != player) && (zone->getType() == ServerInfo_Zone::PublicZone))
|
|| ((playerWhosAsking != player) && (zone->getType() == ServerInfo_Zone::PublicZone))
|
||||||
) {
|
) {
|
||||||
QListIterator<Server_Card *> cardIterator(zone->cards);
|
QListIterator<Server_Card *> cardIterator(zone->cards);
|
||||||
|
@ -590,7 +618,12 @@ void Server_Game::sendGameEventContainer(GameEventContainer *cont, GameEventStor
|
||||||
Server_Player *p = playerIterator.next().value();
|
Server_Player *p = playerIterator.next().value();
|
||||||
const bool playerPrivate = (p->getPlayerId() == privatePlayerId) || (p->getSpectator() && spectatorsSeeEverything);
|
const bool playerPrivate = (p->getPlayerId() == privatePlayerId) || (p->getSpectator() && spectatorsSeeEverything);
|
||||||
if ((recipients.testFlag(GameEventStorageItem::SendToPrivate) && playerPrivate) || (recipients.testFlag(GameEventStorageItem::SendToOthers) && !playerPrivate))
|
if ((recipients.testFlag(GameEventStorageItem::SendToPrivate) && playerPrivate) || (recipients.testFlag(GameEventStorageItem::SendToOthers) && !playerPrivate))
|
||||||
p->sendGameEvent(cont);
|
p->sendGameEvent(*cont);
|
||||||
|
}
|
||||||
|
if (recipients.testFlag(GameEventStorageItem::SendToPrivate)) {
|
||||||
|
cont->set_seconds_elapsed(secondsElapsed);
|
||||||
|
cont->clear_game_id();
|
||||||
|
replay->add_event_list()->CopyFrom(*cont);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete cont;
|
delete cont;
|
||||||
|
@ -631,6 +664,7 @@ ServerInfo_Game Server_Game::getInfo() const
|
||||||
result.set_spectators_allowed(getSpectatorsAllowed());
|
result.set_spectators_allowed(getSpectatorsAllowed());
|
||||||
result.set_spectators_need_password(getSpectatorsNeedPassword());
|
result.set_spectators_need_password(getSpectatorsNeedPassword());
|
||||||
result.set_spectators_count(getSpectatorCount());
|
result.set_spectators_count(getSpectatorCount());
|
||||||
|
result.set_start_time(startTime.toTime_t());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
|
#include <QSet>
|
||||||
|
#include <QDateTime>
|
||||||
#include "server_player.h"
|
#include "server_player.h"
|
||||||
#include "server_response_containers.h"
|
#include "server_response_containers.h"
|
||||||
#include "pb/response.pb.h"
|
#include "pb/response.pb.h"
|
||||||
|
@ -32,6 +34,7 @@
|
||||||
|
|
||||||
class QTimer;
|
class QTimer;
|
||||||
class GameEventContainer;
|
class GameEventContainer;
|
||||||
|
class GameReplay;
|
||||||
class Server_Room;
|
class Server_Room;
|
||||||
class ServerInfo_User;
|
class ServerInfo_User;
|
||||||
|
|
||||||
|
@ -42,6 +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;
|
||||||
bool gameStarted;
|
bool gameStarted;
|
||||||
int gameId;
|
int gameId;
|
||||||
QString description;
|
QString description;
|
||||||
|
@ -56,7 +60,9 @@ private:
|
||||||
bool spectatorsSeeEverything;
|
bool spectatorsSeeEverything;
|
||||||
int inactivityCounter;
|
int inactivityCounter;
|
||||||
int secondsElapsed;
|
int secondsElapsed;
|
||||||
|
QDateTime startTime;
|
||||||
QTimer *pingClock;
|
QTimer *pingClock;
|
||||||
|
GameReplay *replay;
|
||||||
signals:
|
signals:
|
||||||
void sigStartGameIfReady();
|
void sigStartGameIfReady();
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -98,7 +104,8 @@ public:
|
||||||
void nextTurn();
|
void nextTurn();
|
||||||
int getSecondsElapsed() const { return secondsElapsed; }
|
int getSecondsElapsed() const { return secondsElapsed; }
|
||||||
|
|
||||||
QList<ServerInfo_Player> getGameState(Server_Player *playerWhosAsking) const;
|
void sendGameStateToPlayers();
|
||||||
|
QList<ServerInfo_Player> getGameState(Server_Player *playerWhosAsking, bool omniscient = false, bool withUserInfo = false) const;
|
||||||
|
|
||||||
GameEventContainer *prepareGameEvent(const ::google::protobuf::Message &gameEvent, int playerId, GameEventContext *context = 0);
|
GameEventContainer *prepareGameEvent(const ::google::protobuf::Message &gameEvent, int playerId, GameEventContext *context = 0);
|
||||||
GameEventContext prepareGameEventContext(const ::google::protobuf::Message &gameEventContext);
|
GameEventContext prepareGameEventContext(const ::google::protobuf::Message &gameEventContext);
|
||||||
|
|
|
@ -191,13 +191,14 @@ void Server_Player::clearZones()
|
||||||
lastDrawList.clear();
|
lastDrawList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerInfo_PlayerProperties Server_Player::getProperties()
|
ServerInfo_PlayerProperties Server_Player::getProperties(bool withUserInfo)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&game->gameMutex);
|
QMutexLocker locker(&game->gameMutex);
|
||||||
|
|
||||||
ServerInfo_PlayerProperties result;
|
ServerInfo_PlayerProperties result;
|
||||||
result.set_player_id(playerId);
|
result.set_player_id(playerId);
|
||||||
result.mutable_user_info()->CopyFrom(*userInfo);
|
if (withUserInfo)
|
||||||
|
result.mutable_user_info()->CopyFrom(*userInfo);
|
||||||
result.set_spectator(spectator);
|
result.set_spectator(spectator);
|
||||||
result.set_conceded(conceded);
|
result.set_conceded(conceded);
|
||||||
result.set_ready_start(readyStart);
|
result.set_ready_start(readyStart);
|
||||||
|
@ -581,12 +582,12 @@ Response::ResponseCode Server_Player::setCardAttrHelper(GameEventStorage &ges, c
|
||||||
return Response::RespOk;
|
return Response::RespOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server_Player::sendGameEvent(GameEventContainer *cont)
|
void Server_Player::sendGameEvent(const GameEventContainer &cont)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&playerMutex);
|
QMutexLocker locker(&playerMutex);
|
||||||
|
|
||||||
if (handler)
|
if (handler)
|
||||||
handler->sendProtocolItem(*cont);
|
handler->sendProtocolItem(cont);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server_Player::setProtocolHandler(Server_ProtocolHandler *_handler)
|
void Server_Player::setProtocolHandler(Server_ProtocolHandler *_handler)
|
||||||
|
|
|
@ -70,7 +70,7 @@ public:
|
||||||
|
|
||||||
int getPingTime() const { return pingTime; }
|
int getPingTime() const { return pingTime; }
|
||||||
void setPingTime(int _pingTime) { pingTime = _pingTime; }
|
void setPingTime(int _pingTime) { pingTime = _pingTime; }
|
||||||
ServerInfo_PlayerProperties getProperties();
|
ServerInfo_PlayerProperties getProperties(bool withUserInfo);
|
||||||
|
|
||||||
int newCardId();
|
int newCardId();
|
||||||
int newCounterId() const;
|
int newCounterId() const;
|
||||||
|
@ -92,7 +92,7 @@ public:
|
||||||
void unattachCard(GameEventStorage &ges, Server_Card *card);
|
void unattachCard(GameEventStorage &ges, Server_Card *card);
|
||||||
Response::ResponseCode setCardAttrHelper(GameEventStorage &ges, const QString &zone, int cardId, CardAttribute attribute, const QString &attrValue);
|
Response::ResponseCode setCardAttrHelper(GameEventStorage &ges, const QString &zone, int cardId, CardAttribute attribute, const QString &attrValue);
|
||||||
|
|
||||||
void sendGameEvent(GameEventContainer *event);
|
void sendGameEvent(const GameEventContainer &event);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -760,7 +760,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdCreateGame(const Command_Creat
|
||||||
rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event1));
|
rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event1));
|
||||||
|
|
||||||
Event_GameStateChanged event2;
|
Event_GameStateChanged event2;
|
||||||
QListIterator<ServerInfo_Player> gameStateIterator(game->getGameState(creator));
|
QListIterator<ServerInfo_Player> gameStateIterator(game->getGameState(creator, false, true));
|
||||||
while (gameStateIterator.hasNext())
|
while (gameStateIterator.hasNext())
|
||||||
event2.add_player_list()->CopyFrom(gameStateIterator.next());
|
event2.add_player_list()->CopyFrom(gameStateIterator.next());
|
||||||
event2.set_seconds_elapsed(0);
|
event2.set_seconds_elapsed(0);
|
||||||
|
@ -807,7 +807,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGam
|
||||||
rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event1));
|
rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event1));
|
||||||
|
|
||||||
Event_GameStateChanged event2;
|
Event_GameStateChanged event2;
|
||||||
QListIterator<ServerInfo_Player> gameStateIterator(g->getGameState(player));
|
QListIterator<ServerInfo_Player> gameStateIterator(g->getGameState(player, false, true));
|
||||||
while (gameStateIterator.hasNext())
|
while (gameStateIterator.hasNext())
|
||||||
event2.add_player_list()->CopyFrom(gameStateIterator.next());
|
event2.add_player_list()->CopyFrom(gameStateIterator.next());
|
||||||
event2.set_seconds_elapsed(g->getSecondsElapsed());
|
event2.set_seconds_elapsed(g->getSecondsElapsed());
|
||||||
|
@ -854,7 +854,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdDeckSelect(const Command_DeckS
|
||||||
player->setDeck(deck);
|
player->setDeck(deck);
|
||||||
|
|
||||||
Event_PlayerPropertiesChanged event;
|
Event_PlayerPropertiesChanged event;
|
||||||
event.mutable_player_properties()->CopyFrom(player->getProperties());
|
event.mutable_player_properties()->set_deck_hash(deck->getDeckHash().toStdString());
|
||||||
ges.enqueueGameEvent(event, player->getPlayerId());
|
ges.enqueueGameEvent(event, player->getPlayerId());
|
||||||
|
|
||||||
Context_DeckSelect context;
|
Context_DeckSelect context;
|
||||||
|
@ -902,7 +902,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdConcede(const Command_Concede
|
||||||
player->clearZones();
|
player->clearZones();
|
||||||
|
|
||||||
Event_PlayerPropertiesChanged event;
|
Event_PlayerPropertiesChanged event;
|
||||||
event.mutable_player_properties()->CopyFrom(player->getProperties());
|
event.mutable_player_properties()->set_conceded(true);
|
||||||
ges.enqueueGameEvent(event, player->getPlayerId());
|
ges.enqueueGameEvent(event, player->getPlayerId());
|
||||||
ges.setGameEventContext(Context_Concede());
|
ges.setGameEventContext(Context_Concede());
|
||||||
|
|
||||||
|
@ -927,11 +927,13 @@ Response::ResponseCode Server_ProtocolHandler::cmdReadyStart(const Command_Ready
|
||||||
player->setReadyStart(cmd.ready());
|
player->setReadyStart(cmd.ready());
|
||||||
|
|
||||||
Event_PlayerPropertiesChanged event;
|
Event_PlayerPropertiesChanged event;
|
||||||
event.mutable_player_properties()->CopyFrom(player->getProperties());
|
event.mutable_player_properties()->set_ready_start(cmd.ready());
|
||||||
ges.enqueueGameEvent(event, player->getPlayerId());
|
ges.enqueueGameEvent(event, player->getPlayerId());
|
||||||
ges.setGameEventContext(Context_ReadyStart());
|
ges.setGameEventContext(Context_ReadyStart());
|
||||||
|
|
||||||
game->startGameIfReady();
|
if (cmd.ready())
|
||||||
|
game->startGameIfReady();
|
||||||
|
|
||||||
return Response::RespOk;
|
return Response::RespOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "server_logger.h"
|
#include "server_logger.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "passwordhasher.h"
|
#include "passwordhasher.h"
|
||||||
|
#include "pb/game_replay.pb.h"
|
||||||
#include "pb/event_server_message.pb.h"
|
#include "pb/event_server_message.pb.h"
|
||||||
#include "pb/event_server_shutdown.pb.h"
|
#include "pb/event_server_shutdown.pb.h"
|
||||||
#include "pb/event_connection_closed.pb.h"
|
#include "pb/event_connection_closed.pb.h"
|
||||||
|
@ -535,6 +536,47 @@ void Servatrice::statusUpdate()
|
||||||
execSqlQuery(query);
|
execSqlQuery(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Servatrice::storeGameInformation(int secondsElapsed, const QStringList &allPlayersEver, const GameReplay &replay)
|
||||||
|
{
|
||||||
|
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)));
|
||||||
|
|
||||||
|
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 (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.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;
|
||||||
|
|
||||||
|
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(":player_name", playerNames);
|
||||||
|
query2.execBatch();
|
||||||
|
}
|
||||||
|
|
||||||
void Servatrice::scheduleShutdown(const QString &reason, int minutes)
|
void Servatrice::scheduleShutdown(const QString &reason, int minutes)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&serverMutex);
|
QMutexLocker locker(&serverMutex);
|
||||||
|
|
|
@ -29,6 +29,7 @@ class QSettings;
|
||||||
class QSqlQuery;
|
class QSqlQuery;
|
||||||
class QTimer;
|
class QTimer;
|
||||||
|
|
||||||
|
class GameReplay;
|
||||||
class Servatrice;
|
class Servatrice;
|
||||||
class ServerSocketInterface;
|
class ServerSocketInterface;
|
||||||
|
|
||||||
|
@ -82,6 +83,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);
|
||||||
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);
|
||||||
|
|
Loading…
Reference in a new issue