|
@@ -14,126 +14,530 @@
|
|
|
|
|
|
#include "../lib/JsonNode.h"
|
|
|
#include "../lib/network/NetworkServer.h"
|
|
|
+#include "../lib/network/NetworkConnection.h"
|
|
|
|
|
|
-void LobbyServer::sendMessage(const std::shared_ptr<NetworkConnection> & target, const JsonNode & json)
|
|
|
+#include <boost/uuid/uuid_io.hpp>
|
|
|
+#include <boost/uuid/uuid_generators.hpp>
|
|
|
+
|
|
|
+static const auto accountCookieLifetime = std::chrono::hours(24*7);
|
|
|
+
|
|
|
+bool LobbyServer::isAccountNameValid(const std::string & accountName)
|
|
|
+{
|
|
|
+ if (accountName.size() < 4)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (accountName.size() < 20)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ for (auto const & c : accountName)
|
|
|
+ if (!std::isalnum(c))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+std::string LobbyServer::sanitizeChatMessage(const std::string & inputString) const
|
|
|
+{
|
|
|
+ // TODO: sanitize message and remove any "weird" symbols from it
|
|
|
+ return inputString;
|
|
|
+}
|
|
|
+
|
|
|
+NetworkConnectionPtr LobbyServer::findAccount(const std::string & accountID)
|
|
|
{
|
|
|
- //FIXME: copy-paste from LobbyClient::sendMessage
|
|
|
+ for (auto const & account : activeAccounts)
|
|
|
+ if (account.second.accountID == accountID)
|
|
|
+ return account.first;
|
|
|
+
|
|
|
+ return nullptr;
|
|
|
+}
|
|
|
+
|
|
|
+NetworkConnectionPtr LobbyServer::findGameRoom(const std::string & gameRoomID)
|
|
|
+{
|
|
|
+ for (auto const & account : activeGameRooms)
|
|
|
+ if (account.second.roomID == gameRoomID)
|
|
|
+ return account.first;
|
|
|
+
|
|
|
+ return nullptr;
|
|
|
+}
|
|
|
+
|
|
|
+void LobbyServer::sendMessage(const NetworkConnectionPtr & target, const JsonNode & json)
|
|
|
+{
|
|
|
+ //NOTE: copy-paste from LobbyClient::sendMessage
|
|
|
std::string payloadString = json.toJson(true);
|
|
|
|
|
|
- // FIXME: find better approach
|
|
|
- uint8_t * payloadBegin = reinterpret_cast<uint8_t *>(payloadString.data());
|
|
|
- uint8_t * payloadEnd = payloadBegin + payloadString.size();
|
|
|
+ // TODO: find better approach
|
|
|
+ const uint8_t * payloadBegin = reinterpret_cast<uint8_t *>(payloadString.data());
|
|
|
+ const uint8_t * payloadEnd = payloadBegin + payloadString.size();
|
|
|
|
|
|
std::vector<uint8_t> payloadBuffer(payloadBegin, payloadEnd);
|
|
|
|
|
|
networkServer->sendPacket(target, payloadBuffer);
|
|
|
}
|
|
|
|
|
|
-void LobbyServer::onTimer()
|
|
|
+void LobbyServer::sendAccountCreated(const NetworkConnectionPtr & target, const std::string & accountID, const std::string & accountCookie)
|
|
|
{
|
|
|
- // no-op
|
|
|
+ JsonNode reply;
|
|
|
+ reply["type"].String() = "accountCreated";
|
|
|
+ reply["accountID"].String() = accountID;
|
|
|
+ reply["accountCookie"].String() = accountCookie;
|
|
|
+ sendMessage(target, reply);
|
|
|
}
|
|
|
|
|
|
-void LobbyServer::onNewConnection(const std::shared_ptr<NetworkConnection> & connection)
|
|
|
-{}
|
|
|
+void LobbyServer::sendInviteReceived(const NetworkConnectionPtr & target, const std::string & accountID, const std::string & gameRoomID)
|
|
|
+{
|
|
|
+ JsonNode reply;
|
|
|
+ reply["type"].String() = "inviteReceived";
|
|
|
+ reply["accountID"].String() = accountID;
|
|
|
+ reply["gameRoomID"].String() = gameRoomID;
|
|
|
+ sendMessage(target, reply);
|
|
|
+}
|
|
|
|
|
|
-void LobbyServer::onDisconnected(const std::shared_ptr<NetworkConnection> & connection)
|
|
|
+void LobbyServer::sendLoginFailed(const NetworkConnectionPtr & target, const std::string & reason)
|
|
|
{
|
|
|
- activeAccounts.erase(connection);
|
|
|
+ JsonNode reply;
|
|
|
+ reply["type"].String() = "loginFailed";
|
|
|
+ reply["reason"].String() = reason;
|
|
|
+ sendMessage(target, reply);
|
|
|
}
|
|
|
|
|
|
-void LobbyServer::onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message)
|
|
|
+void LobbyServer::sendLoginSuccess(const NetworkConnectionPtr & target, const std::string & accountCookie)
|
|
|
{
|
|
|
- // FIXME: find better approach
|
|
|
- JsonNode json(message.data(), message.size());
|
|
|
+ JsonNode reply;
|
|
|
+ reply["type"].String() = "loginSuccess";
|
|
|
+ reply["accountCookie"].String() = accountCookie;
|
|
|
+ sendMessage(target, reply);
|
|
|
+}
|
|
|
+
|
|
|
+void LobbyServer::sendChatHistory(const NetworkConnectionPtr & target, const std::vector<LobbyChatMessage> & history)
|
|
|
+{
|
|
|
+ JsonNode reply;
|
|
|
+ reply["type"].String() = "chatHistory";
|
|
|
+
|
|
|
+ for(const auto & message : boost::adaptors::reverse(history))
|
|
|
+ {
|
|
|
+ JsonNode jsonEntry;
|
|
|
|
|
|
- if(json["type"].String() == "sendChatMessage")
|
|
|
- return receiveSendChatMessage(connection, json);
|
|
|
+ jsonEntry["messageText"].String() = message.messageText;
|
|
|
+ jsonEntry["senderName"].String() = message.sender;
|
|
|
+ jsonEntry["ageSeconds"].Integer() = message.age.count();
|
|
|
|
|
|
- if(json["type"].String() == "authentication")
|
|
|
- return receiveAuthentication(connection, json);
|
|
|
+ reply["messages"].Vector().push_back(jsonEntry);
|
|
|
+ }
|
|
|
|
|
|
- if(json["type"].String() == "joinGameRoom")
|
|
|
- return receiveJoinGameRoom(connection, json);
|
|
|
+ sendMessage(target, reply);
|
|
|
}
|
|
|
|
|
|
-void LobbyServer::receiveSendChatMessage(const std::shared_ptr<NetworkConnection> & connection, const JsonNode & json)
|
|
|
+void LobbyServer::broadcastActiveAccounts()
|
|
|
{
|
|
|
- if(activeAccounts.count(connection) == 0)
|
|
|
- return; // unauthenticated
|
|
|
+ auto activeAccountsStats = database->getActiveAccounts();
|
|
|
|
|
|
- std::string senderName = activeAccounts[connection].accountName;
|
|
|
- std::string messageText = json["messageText"].String();
|
|
|
+ JsonNode reply;
|
|
|
+ reply["type"].String() = "activeAccounts";
|
|
|
+
|
|
|
+ for(const auto & account : activeAccountsStats)
|
|
|
+ {
|
|
|
+ JsonNode jsonEntry;
|
|
|
+ jsonEntry["accountID"].String() = account.accountID;
|
|
|
+ jsonEntry["displayName"].String() = account.displayName;
|
|
|
+// jsonEntry["status"].String() = account.status;
|
|
|
+ reply["accounts"].Vector().push_back(jsonEntry);
|
|
|
+ }
|
|
|
+
|
|
|
+ for(const auto & connection : activeAccounts)
|
|
|
+ sendMessage(connection.first, reply);
|
|
|
+}
|
|
|
|
|
|
- database->insertChatMessage(senderName, "general", "english", messageText);
|
|
|
+void LobbyServer::broadcastActiveGameRooms()
|
|
|
+{
|
|
|
+ auto activeGameRoomStats = database->getActiveGameRooms();
|
|
|
+ JsonNode reply;
|
|
|
+ reply["type"].String() = "activeGameRooms";
|
|
|
+
|
|
|
+ for(const auto & gameRoom : activeGameRoomStats)
|
|
|
+ {
|
|
|
+ JsonNode jsonEntry;
|
|
|
+ jsonEntry["gameRoomID"].String() = gameRoom.roomUUID;
|
|
|
+ jsonEntry["status"].String() = gameRoom.roomStatus;
|
|
|
+ jsonEntry["status"].Integer() = gameRoom.playersCount;
|
|
|
+ jsonEntry["status"].Integer() = gameRoom.playersLimit;
|
|
|
+ reply["gameRooms"].Vector().push_back(jsonEntry);
|
|
|
+ }
|
|
|
+
|
|
|
+ for(const auto & connection : activeAccounts)
|
|
|
+ sendMessage(connection.first, reply);
|
|
|
+}
|
|
|
|
|
|
+void LobbyServer::sendAccountJoinsRoom(const NetworkConnectionPtr & target, const std::string & accountID)
|
|
|
+{
|
|
|
+ JsonNode reply;
|
|
|
+ reply["type"].String() = "accountJoinsRoom";
|
|
|
+ reply["accountID"].String() = accountID;
|
|
|
+ sendMessage(target, reply);
|
|
|
+}
|
|
|
+
|
|
|
+void LobbyServer::sendJoinRoomSuccess(const NetworkConnectionPtr & target, const std::string & gameRoomID)
|
|
|
+{
|
|
|
+ JsonNode reply;
|
|
|
+ reply["type"].String() = "joinRoomSuccess";
|
|
|
+ reply["gameRoomID"].String() = gameRoomID;
|
|
|
+ sendMessage(target, reply);
|
|
|
+}
|
|
|
+
|
|
|
+void LobbyServer::sendChatMessage(const NetworkConnectionPtr & target, const std::string & roomMode, const std::string & roomName, const std::string & senderName, const std::string & messageText)
|
|
|
+{
|
|
|
JsonNode reply;
|
|
|
reply["type"].String() = "chatMessage";
|
|
|
reply["messageText"].String() = messageText;
|
|
|
reply["senderName"].String() = senderName;
|
|
|
+ reply["roomMode"].String() = roomMode;
|
|
|
+ reply["roomName"].String() = roomName;
|
|
|
|
|
|
- for(const auto & connection : activeAccounts)
|
|
|
- sendMessage(connection.first, reply);
|
|
|
+ sendMessage(target, reply);
|
|
|
}
|
|
|
|
|
|
-void LobbyServer::receiveAuthentication(const std::shared_ptr<NetworkConnection> & connection, const JsonNode & json)
|
|
|
+void LobbyServer::onTimer()
|
|
|
{
|
|
|
- std::string accountName = json["accountName"].String();
|
|
|
+ // no-op
|
|
|
+}
|
|
|
|
|
|
- // TODO: account cookie check
|
|
|
- // TODO: account password check
|
|
|
- // TODO: protocol version number
|
|
|
- // TODO: client/server mode flag
|
|
|
- // TODO: client language
|
|
|
+void LobbyServer::onNewConnection(const NetworkConnectionPtr & connection)
|
|
|
+{
|
|
|
+ // no-op - waiting for incoming data
|
|
|
+}
|
|
|
+
|
|
|
+void LobbyServer::onDisconnected(const NetworkConnectionPtr & connection)
|
|
|
+{
|
|
|
+ // NOTE: lost connection can be in only one of these lists (or in none of them)
|
|
|
+ // calling on all possible containers since calling std::map::erase() with non-existing key is legal
|
|
|
+ activeAccounts.erase(connection);
|
|
|
+ activeProxies.erase(connection);
|
|
|
+ activeGameRooms.erase(connection);
|
|
|
+
|
|
|
+ broadcastActiveAccounts();
|
|
|
+ broadcastActiveGameRooms();
|
|
|
+}
|
|
|
+
|
|
|
+void LobbyServer::onPacketReceived(const NetworkConnectionPtr & connection, const std::vector<uint8_t> & message)
|
|
|
+{
|
|
|
+ // proxy connection - no processing, only redirect
|
|
|
+ if (activeProxies.count(connection))
|
|
|
+ {
|
|
|
+ auto lockedPtr = activeProxies.at(connection).lock();
|
|
|
+ if (lockedPtr)
|
|
|
+ lockedPtr->sendPacket(message);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- activeAccounts[connection].accountName = accountName;
|
|
|
+ JsonNode json(message.data(), message.size());
|
|
|
+
|
|
|
+ // TODO: check for json parsing errors
|
|
|
+ // TODO: validate json based on received message type
|
|
|
|
|
|
+ // communication messages from vcmiclient
|
|
|
+ if (activeAccounts.count(connection))
|
|
|
{
|
|
|
- JsonNode reply;
|
|
|
- reply["type"].String() = "authentication";
|
|
|
+ if(json["type"].String() == "sendChatMessage")
|
|
|
+ return receiveSendChatMessage(connection, json);
|
|
|
+
|
|
|
+ if(json["type"].String() == "openGameRoom")
|
|
|
+ return receiveOpenGameRoom(connection, json);
|
|
|
+
|
|
|
+ if(json["type"].String() == "joinGameRoom")
|
|
|
+ return receiveJoinGameRoom(connection, json);
|
|
|
+
|
|
|
+ if(json["type"].String() == "sendInvite")
|
|
|
+ return receiveSendInvite(connection, json);
|
|
|
+
|
|
|
+ if(json["type"].String() == "declineInvite")
|
|
|
+ return receiveDeclineInvite(connection, json);
|
|
|
|
|
|
- sendMessage(connection, reply);
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
- auto history = database->getRecentMessageHistory();
|
|
|
+ // communication messages from vcmiserver
|
|
|
+ if (activeGameRooms.count(connection))
|
|
|
+ {
|
|
|
+ if(json["type"].String() == "leaveGameRoom")
|
|
|
+ return receiveLeaveGameRoom(connection, json);
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // unauthorized connections - permit only login or register attempts
|
|
|
+ if(json["type"].String() == "clientLogin")
|
|
|
+ return receiveClientLogin(connection, json);
|
|
|
+
|
|
|
+ if(json["type"].String() == "clientRegister")
|
|
|
+ return receiveClientRegister(connection, json);
|
|
|
|
|
|
+ if(json["type"].String() == "serverLogin")
|
|
|
+ return receiveServerLogin(connection, json);
|
|
|
+
|
|
|
+ if(json["type"].String() == "clientProxyLogin")
|
|
|
+ return receiveClientProxyLogin(connection, json);
|
|
|
+
|
|
|
+ if(json["type"].String() == "serverProxyLogin")
|
|
|
+ return receiveServerProxyLogin(connection, json);
|
|
|
+
|
|
|
+ // TODO: add logging of suspicious connections.
|
|
|
+ networkServer->closeConnection(connection);
|
|
|
+}
|
|
|
+
|
|
|
+void LobbyServer::receiveSendChatMessage(const NetworkConnectionPtr & connection, const JsonNode & json)
|
|
|
+{
|
|
|
+ std::string senderName = activeAccounts[connection].accountID;
|
|
|
+ std::string messageText = json["messageText"].String();
|
|
|
+ std::string messageTextClean = sanitizeChatMessage(messageText);
|
|
|
+
|
|
|
+ if (messageTextClean.empty())
|
|
|
+ return;
|
|
|
+
|
|
|
+ database->insertChatMessage(senderName, "global", "english", messageText);
|
|
|
+
|
|
|
+ for(const auto & connection : activeAccounts)
|
|
|
+ sendChatMessage(connection.first, "global", "english", senderName, messageText);
|
|
|
+}
|
|
|
+
|
|
|
+void LobbyServer::receiveClientRegister(const NetworkConnectionPtr & connection, const JsonNode & json)
|
|
|
+{
|
|
|
+ std::string accountID = json["accountID"].String();
|
|
|
+ std::string displayName = json["displayName"].String();
|
|
|
+ std::string language = json["language"].String();
|
|
|
+
|
|
|
+ if (database->isAccountExists(accountID))
|
|
|
+ return sendLoginFailed(connection, "Account name already in use");
|
|
|
+
|
|
|
+ if (isAccountNameValid(accountID))
|
|
|
+ return sendLoginFailed(connection, "Illegal account name");
|
|
|
+
|
|
|
+ std::string accountCookie = boost::uuids::to_string(boost::uuids::random_generator()());
|
|
|
+
|
|
|
+ database->insertAccount(accountID, displayName);
|
|
|
+ database->insertAccessCookie(accountID, accountCookie);
|
|
|
+
|
|
|
+ sendAccountCreated(connection, accountID, accountCookie);
|
|
|
+}
|
|
|
+
|
|
|
+void LobbyServer::receiveClientLogin(const NetworkConnectionPtr & connection, const JsonNode & json)
|
|
|
+{
|
|
|
+ std::string accountID = json["accountID"].String();
|
|
|
+ std::string accountCookie = json["accountCookie"].String();
|
|
|
+ std::string language = json["language"].String();
|
|
|
+ std::string version = json["version"].String();
|
|
|
+
|
|
|
+ if (!database->isAccountExists(accountID))
|
|
|
+ return sendLoginFailed(connection, "Account not found");
|
|
|
+
|
|
|
+ auto clientCookieStatus = database->getAccountCookieStatus(accountID, accountCookie, accountCookieLifetime);
|
|
|
+
|
|
|
+ if (clientCookieStatus == LobbyCookieStatus::INVALID)
|
|
|
+ return sendLoginFailed(connection, "Authentification failure");
|
|
|
+
|
|
|
+ // prolong existing cookie
|
|
|
+ database->updateAccessCookie(accountID, accountCookie);
|
|
|
+ database->updateAccountLoginTime(accountID);
|
|
|
+
|
|
|
+ std::string displayName = database->getAccountDisplayName(accountID);
|
|
|
+
|
|
|
+ activeAccounts[connection].accountID = accountID;
|
|
|
+ activeAccounts[connection].displayName = displayName;
|
|
|
+ activeAccounts[connection].version = version;
|
|
|
+ activeAccounts[connection].language = language;
|
|
|
+
|
|
|
+ sendLoginSuccess(connection, accountCookie);
|
|
|
+ sendChatHistory(connection, database->getRecentMessageHistory());
|
|
|
+
|
|
|
+ // send active accounts list to new account
|
|
|
+ // and update acount list to everybody else
|
|
|
+ broadcastActiveAccounts();
|
|
|
+}
|
|
|
+
|
|
|
+void LobbyServer::receiveServerLogin(const NetworkConnectionPtr & connection, const JsonNode & json)
|
|
|
+{
|
|
|
+ std::string gameRoomID = json["gameRoomID"].String();
|
|
|
+ std::string accountID = json["accountID"].String();
|
|
|
+ std::string accountCookie = json["accountCookie"].String();
|
|
|
+ std::string version = json["version"].String();
|
|
|
+
|
|
|
+ auto clientCookieStatus = database->getAccountCookieStatus(accountID, accountCookie, accountCookieLifetime);
|
|
|
+
|
|
|
+ if (clientCookieStatus == LobbyCookieStatus::INVALID)
|
|
|
+ {
|
|
|
+ sendLoginFailed(connection, "Invalid credentials");
|
|
|
+ }
|
|
|
+ else
|
|
|
{
|
|
|
- JsonNode reply;
|
|
|
- reply["type"].String() = "chatHistory";
|
|
|
+ database->insertGameRoom(gameRoomID, accountID);
|
|
|
+ activeGameRooms[connection].roomID = gameRoomID;
|
|
|
+ sendLoginSuccess(connection, accountCookie);
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- for(const auto & message : boost::adaptors::reverse(history))
|
|
|
+void LobbyServer::receiveClientProxyLogin(const NetworkConnectionPtr & connection, const JsonNode & json)
|
|
|
+{
|
|
|
+ std::string gameRoomID = json["gameRoomID"].String();
|
|
|
+ std::string accountID = json["accountID"].String();
|
|
|
+ std::string accountCookie = json["accountCookie"].String();
|
|
|
+
|
|
|
+ auto clientCookieStatus = database->getAccountCookieStatus(accountID, accountCookie, accountCookieLifetime);
|
|
|
+
|
|
|
+ if (clientCookieStatus != LobbyCookieStatus::INVALID)
|
|
|
+ {
|
|
|
+ for (auto & proxyEntry : awaitingProxies)
|
|
|
{
|
|
|
- JsonNode jsonEntry;
|
|
|
+ if (proxyEntry.accountID != accountID)
|
|
|
+ continue;
|
|
|
+ if (proxyEntry.roomID != gameRoomID)
|
|
|
+ continue;
|
|
|
|
|
|
- jsonEntry["messageText"].String() = message.messageText;
|
|
|
- jsonEntry["senderName"].String() = message.sender;
|
|
|
- jsonEntry["ageSeconds"].Integer() = message.age.count();
|
|
|
+ proxyEntry.accountConnection = connection;
|
|
|
|
|
|
- reply["messages"].Vector().push_back(jsonEntry);
|
|
|
+ auto gameRoomConnection = proxyEntry.roomConnection.lock();
|
|
|
+
|
|
|
+ if (gameRoomConnection)
|
|
|
+ {
|
|
|
+ activeProxies[gameRoomConnection] = connection;
|
|
|
+ activeProxies[connection] = gameRoomConnection;
|
|
|
+ }
|
|
|
+ return;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- sendMessage(connection, reply);
|
|
|
+ networkServer->closeConnection(connection);
|
|
|
+}
|
|
|
+
|
|
|
+void LobbyServer::receiveServerProxyLogin(const NetworkConnectionPtr & connection, const JsonNode & json)
|
|
|
+{
|
|
|
+ std::string gameRoomID = json["gameRoomID"].String();
|
|
|
+ std::string guestAccountID = json["guestAccountID"].String();
|
|
|
+ std::string hostCookie = json["hostCookie"].String();
|
|
|
+
|
|
|
+ auto clientCookieStatus = database->getGameRoomCookieStatus(gameRoomID, hostCookie, accountCookieLifetime);
|
|
|
+
|
|
|
+ if (clientCookieStatus != LobbyCookieStatus::INVALID)
|
|
|
+ {
|
|
|
+ NetworkConnectionPtr targetAccount = findAccount(guestAccountID);
|
|
|
+
|
|
|
+ if (targetAccount == nullptr)
|
|
|
+ return; // unknown / disconnected account
|
|
|
+
|
|
|
+ sendJoinRoomSuccess(targetAccount, gameRoomID);
|
|
|
+
|
|
|
+ AwaitingProxyState proxy;
|
|
|
+ proxy.accountID = guestAccountID;
|
|
|
+ proxy.roomID = gameRoomID;
|
|
|
+ proxy.roomConnection = connection;
|
|
|
+ awaitingProxies.push_back(proxy);
|
|
|
+ return;
|
|
|
}
|
|
|
+
|
|
|
+ networkServer->closeConnection(connection);
|
|
|
}
|
|
|
|
|
|
-void LobbyServer::receiveJoinGameRoom(const std::shared_ptr<NetworkConnection> & connection, const JsonNode & json)
|
|
|
+void LobbyServer::receiveOpenGameRoom(const NetworkConnectionPtr & connection, const JsonNode & json)
|
|
|
{
|
|
|
- if(activeAccounts.count(connection) == 0)
|
|
|
- return; // unauthenticated
|
|
|
+ std::string hostAccountID = json["hostAccountID"].String();
|
|
|
+ std::string accountID = activeAccounts[connection].accountID;
|
|
|
+
|
|
|
+ if(database->isPlayerInGameRoom(accountID))
|
|
|
+ return; // only 1 room per player allowed
|
|
|
|
|
|
- std::string senderName = activeAccounts[connection].accountName;
|
|
|
+ std::string gameRoomID = database->getIdleGameRoom(hostAccountID);
|
|
|
+ if (gameRoomID.empty())
|
|
|
+ return;
|
|
|
|
|
|
- if(database->isPlayerInGameRoom(senderName))
|
|
|
+ std::string roomType = json["roomType"].String();
|
|
|
+ if (roomType == "public")
|
|
|
+ database->setGameRoomStatus(gameRoomID, LobbyRoomState::PUBLIC);
|
|
|
+ if (roomType == "private")
|
|
|
+ database->setGameRoomStatus(gameRoomID, LobbyRoomState::PRIVATE);
|
|
|
+
|
|
|
+ // TODO: additional flags / initial settings, e.g. allowCheats
|
|
|
+ // TODO: connection mode: direct or proxy. For now direct is assumed
|
|
|
+
|
|
|
+ broadcastActiveGameRooms();
|
|
|
+ sendJoinRoomSuccess(connection, gameRoomID);
|
|
|
+}
|
|
|
+
|
|
|
+void LobbyServer::receiveJoinGameRoom(const NetworkConnectionPtr & connection, const JsonNode & json)
|
|
|
+{
|
|
|
+ std::string gameRoomID = json["gameRoomID"].String();
|
|
|
+ std::string accountID = activeAccounts[connection].accountID;
|
|
|
+
|
|
|
+ if(database->isPlayerInGameRoom(accountID))
|
|
|
return; // only 1 room per player allowed
|
|
|
|
|
|
- // TODO: roomType: private, public
|
|
|
- // TODO: additional flags, e.g. allowCheats
|
|
|
- // TODO: connection mode: direct or proxy
|
|
|
+ NetworkConnectionPtr targetRoom = findGameRoom(gameRoomID);
|
|
|
+
|
|
|
+ if (targetRoom == nullptr)
|
|
|
+ return; // unknown / disconnected room
|
|
|
+
|
|
|
+ auto roomStatus = database->getGameRoomStatus(gameRoomID);
|
|
|
+
|
|
|
+ if (roomStatus == LobbyRoomState::PRIVATE)
|
|
|
+ {
|
|
|
+ if (database->getAccountInviteStatus(accountID, gameRoomID) != LobbyInviteStatus::INVITED)
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (database->getGameRoomFreeSlots(gameRoomID) == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ sendAccountJoinsRoom(targetRoom, accountID);
|
|
|
+ //No reply to client - will be sent once match server establishes proxy connection with lobby
|
|
|
+
|
|
|
+ broadcastActiveGameRooms();
|
|
|
+}
|
|
|
+
|
|
|
+void LobbyServer::receiveLeaveGameRoom(const NetworkConnectionPtr & connection, const JsonNode & json)
|
|
|
+{
|
|
|
+ std::string gameRoomID = json["gameRoomID"].String();
|
|
|
+ std::string senderName = activeAccounts[connection].accountID;
|
|
|
+
|
|
|
+ if(!database->isPlayerInGameRoom(senderName, gameRoomID))
|
|
|
+ return;
|
|
|
+
|
|
|
+ broadcastActiveGameRooms();
|
|
|
+}
|
|
|
+
|
|
|
+void LobbyServer::receiveSendInvite(const NetworkConnectionPtr & connection, const JsonNode & json)
|
|
|
+{
|
|
|
+ std::string senderName = activeAccounts[connection].accountID;
|
|
|
+ std::string accountID = json["accountID"].String();
|
|
|
+ std::string gameRoomID = database->getAccountGameRoom(senderName);
|
|
|
+
|
|
|
+ auto targetAccount = findAccount(accountID);
|
|
|
+
|
|
|
+ if (!targetAccount)
|
|
|
+ return; // target player does not exists or offline
|
|
|
+
|
|
|
+ if(!database->isPlayerInGameRoom(senderName))
|
|
|
+ return; // current player is not in room
|
|
|
+
|
|
|
+ if(database->isPlayerInGameRoom(accountID))
|
|
|
+ return; // target player is busy
|
|
|
+
|
|
|
+ if (database->getAccountInviteStatus(accountID, gameRoomID) != LobbyInviteStatus::NOT_INVITED)
|
|
|
+ return; // already has invite
|
|
|
+
|
|
|
+ database->insertGameRoomInvite(accountID, gameRoomID);
|
|
|
+ sendInviteReceived(targetAccount, senderName, gameRoomID);
|
|
|
+}
|
|
|
+
|
|
|
+void LobbyServer::receiveDeclineInvite(const NetworkConnectionPtr & connection, const JsonNode & json)
|
|
|
+{
|
|
|
+ std::string accountID = activeAccounts[connection].accountID;
|
|
|
+ std::string gameRoomID = json["gameRoomID"].String();
|
|
|
+
|
|
|
+ if (database->getAccountInviteStatus(accountID, gameRoomID) != LobbyInviteStatus::INVITED)
|
|
|
+ return; // already has invite
|
|
|
+
|
|
|
+ database->deleteGameRoomInvite(accountID, gameRoomID);
|
|
|
}
|
|
|
|
|
|
LobbyServer::~LobbyServer() = default;
|
|
|
|
|
|
-LobbyServer::LobbyServer(const std::string & databasePath)
|
|
|
+LobbyServer::LobbyServer(const boost::filesystem::path & databasePath)
|
|
|
: database(new LobbyDatabase(databasePath))
|
|
|
, networkServer(new NetworkServer(*this))
|
|
|
{
|