/* * lobby.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ #pragma once #include #include const unsigned int ProtocolVersion = 4; const std::string ProtocolEncoding = "utf8"; class ProtocolError: public std::runtime_error { public: ProtocolError(const char * w): std::runtime_error(w) {} }; enum ProtocolConsts { //client consts GREETING, USERNAME, MESSAGE, VERSION, CREATE, JOIN, LEAVE, KICK, READY, FORCESTART, HERE, ALIVE, HOSTMODE, //server consts SESSIONS, CREATED, JOINED, KICKED, SRVERROR, CHAT, START, STATUS, HOST, MODS, CLIENTMODS, USERS, HEALTH, GAMEMODE }; const QMap ProtocolStrings { //=== client commands === //handshaking with server //%1: first byte is protocol_version, then size of encoding string in bytes, then encoding string //%2: client name //%3: VCMI version {GREETING, "%1%2%3"}, //[unsupported] autorization with username //%1: username {USERNAME, "%1"}, //sending message to the chat //%1: message text {MESSAGE, "%1"}, //create new room //%1: room name //%2: password for the room //%3: max number of players //%4: mods used by host // each mod has a format modname&modversion, mods should be separated by ; symbol {CREATE, "%1%2%3%4"}, //join to the room //%1: room name //%2: password for the room //%3: list of mods used by player // each mod has a format modname&modversion, mods should be separated by ; symbol {JOIN, "%1%2%3"}, //leave the room //%1: room name {LEAVE, "%1"}, //kick user from the current room //%1: player username {KICK, "%1"}, //signal that player is ready for game //%1: room name {READY, "%1"}, //[unsupported] start session immediately //%1: room name {FORCESTART, "%1"}, //request user list {HERE, ""}, //used as reponse to healcheck {ALIVE, ""}, //host sets game mode (new game or load game) //%1: game mode - 0 for new game, 1 for load game {HOSTMODE, "%1"}, //=== server commands === //server commands are started from :>>, arguments are enumerated by : symbol //new session was created //arg[0]: room name {CREATED, "CREATED"}, //list of existing sessions //arg[0]: amount of sessions, following arguments depending on it //arg[x]: session name //arg[x+1]: amount of players in the session //arg[x+2]: total amount of players allowed //arg[x+3]: True if session is protected by password {SESSIONS, "SESSIONS"}, //user has joined to the session //arg[0]: session name //arg[1]: username (who was joined) {JOINED, "JOIN"}, //user has left the session //arg[0]: session name //arg[1]: username (who has left) {KICKED, "KICK"}, //session has been started //arg[0]: session name //arg[1]: uuid to be used for connection {START, "START"}, //host ownership for the game session //arg[0]: uuid to be used by vcmiserver //arg[1]: amount of players (clients) to be connected {HOST, "HOST"}, //room status //arg[0]: amount of players, following arguments depending on it //arg[x]: player username //arg[x+1]: True if player is ready {STATUS, "STATUS"}, //joined_players:player_name:is_ready //server error //arg[0]: error message {SRVERROR, "ERROR"}, //mods used in the session by host player //arg[0]: amount of mods, following arguments depending on it //arg[x]: mod name //arg[x+1]: mod version {MODS, "MODS"}, //mods used by user //arg[0]: username //arg[1]: amount of mods, following arguments depending on it //arg[x]: mod name //arg[x+1]: mod version {CLIENTMODS, "MODSOTHER"}, //received chat message //arg[0]: sender username //arg[1]: message text {CHAT, "MSG"}, //list of users currently in lobby //arg[0]: amount of players, following arguments depend on it //arg[x]: username //arg[x+1]: room (empty if not in the room) {USERS, "USERS"}, //healthcheck from server {HEALTH, "HEALTH"}, //game mode (new game or load game) set by host //arg[0]: game mode {GAMEMODE, "GAMEMODE"}, }; class ServerCommand { public: ServerCommand(ProtocolConsts, const QStringList & arguments); const ProtocolConsts command; const QStringList arguments; }; class SocketLobby : public QObject { Q_OBJECT public: explicit SocketLobby(QObject *parent = 0); void connectServer(const QString & host, int port, const QString & username, int timeout); void disconnectServer(); void requestNewSession(const QString & session, int totalPlayers, const QString & pswd, const QMap & mods); void requestJoinSession(const QString & session, const QString & pswd, const QMap & mods); void requestLeaveSession(const QString & session); void requestReadySession(const QString & session); void send(const QString &); signals: void text(QString); void receive(QString); void disconnect(); public slots: void connected(); void disconnected(); void bytesWritten(qint64 bytes); void readyRead(); private: QTcpSocket *socket; bool isConnected = false; QString username; }; QString prepareModsClientString(const QMap & mods);