GlobalLobbyProcessor.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. * GlobalLobbyProcessor.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "GlobalLobbyProcessor.h"
  12. #include "CVCMIServer.h"
  13. #include "../lib/CConfigHandler.h"
  14. #include "../lib/json/JsonUtils.h"
  15. #include "../lib/VCMI_Lib.h"
  16. #include "../lib/modding/CModHandler.h"
  17. #include "../lib/modding/ModDescription.h"
  18. #include "../lib/modding/ModVerificationInfo.h"
  19. GlobalLobbyProcessor::GlobalLobbyProcessor(CVCMIServer & owner)
  20. : owner(owner)
  21. {
  22. logGlobal->info("Connecting to lobby server");
  23. establishNewConnection();
  24. }
  25. void GlobalLobbyProcessor::establishNewConnection()
  26. {
  27. std::string hostname = settings["lobby"]["hostname"].String();
  28. uint16_t port = settings["lobby"]["port"].Integer();
  29. owner.getNetworkHandler().connectToRemote(*this, hostname, port);
  30. }
  31. void GlobalLobbyProcessor::onDisconnected(const std::shared_ptr<INetworkConnection> & connection, const std::string & errorMessage)
  32. {
  33. if (connection == controlConnection)
  34. {
  35. owner.setState(EServerState::SHUTDOWN);
  36. return;
  37. }
  38. else
  39. {
  40. for (auto const & proxy : proxyConnections)
  41. {
  42. if (proxy.second != connection)
  43. continue;
  44. if (owner.getState() == EServerState::LOBBY)
  45. {
  46. JsonNode message;
  47. message["type"].String() = "leaveGameRoom";
  48. message["accountID"].String() = proxy.first;
  49. sendMessage(controlConnection, message);
  50. }
  51. proxyConnections.erase(proxy.first);
  52. // player disconnected
  53. owner.onDisconnected(connection, errorMessage);
  54. return;
  55. }
  56. }
  57. }
  58. void GlobalLobbyProcessor::onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<std::byte> & message)
  59. {
  60. if (connection == controlConnection)
  61. {
  62. JsonNode json(message.data(), message.size(), "<lobby network packet>");
  63. if(json["type"].String() == "operationFailed")
  64. return receiveOperationFailed(json);
  65. if(json["type"].String() == "serverLoginSuccess")
  66. return receiveServerLoginSuccess(json);
  67. if(json["type"].String() == "accountJoinsRoom")
  68. return receiveAccountJoinsRoom(json);
  69. logGlobal->error("Received unexpected message from lobby server of type '%s' ", json["type"].String());
  70. }
  71. else
  72. {
  73. // received game message via proxy connection
  74. owner.onPacketReceived(connection, message);
  75. }
  76. }
  77. void GlobalLobbyProcessor::receiveOperationFailed(const JsonNode & json)
  78. {
  79. logGlobal->info("Lobby: Failed to login into a lobby server!");
  80. owner.setState(EServerState::SHUTDOWN);
  81. }
  82. void GlobalLobbyProcessor::receiveServerLoginSuccess(const JsonNode & json)
  83. {
  84. // no-op, wait just for any new commands from lobby
  85. logGlobal->info("Lobby: Successfully connected to lobby server");
  86. owner.startAcceptingIncomingConnections();
  87. }
  88. void GlobalLobbyProcessor::receiveAccountJoinsRoom(const JsonNode & json)
  89. {
  90. std::string accountID = json["accountID"].String();
  91. logGlobal->info("Lobby: Account %s will join our room!", accountID);
  92. assert(proxyConnections.count(accountID) == 0);
  93. proxyConnections[accountID] = nullptr;
  94. establishNewConnection();
  95. }
  96. void GlobalLobbyProcessor::onConnectionFailed(const std::string & errorMessage)
  97. {
  98. owner.setState(EServerState::SHUTDOWN);
  99. }
  100. void GlobalLobbyProcessor::onConnectionEstablished(const std::shared_ptr<INetworkConnection> & connection)
  101. {
  102. if (controlConnection == nullptr)
  103. {
  104. controlConnection = connection;
  105. logGlobal->info("Connection to lobby server established");
  106. JsonNode toSend;
  107. toSend["type"].String() = "serverLogin";
  108. toSend["gameRoomID"].String() = owner.uuid;
  109. toSend["accountID"].String() = getHostAccountID();
  110. toSend["accountCookie"].String() = getHostAccountCookie();
  111. toSend["version"].String() = VCMI_VERSION_STRING;
  112. toSend["mods"] = getHostModList();
  113. sendMessage(connection, toSend);
  114. }
  115. else
  116. {
  117. // Proxy connection for a player
  118. std::string guestAccountID;
  119. for (auto const & proxies : proxyConnections)
  120. if (proxies.second == nullptr)
  121. guestAccountID = proxies.first;
  122. JsonNode toSend;
  123. toSend["type"].String() = "serverProxyLogin";
  124. toSend["gameRoomID"].String() = owner.uuid;
  125. toSend["guestAccountID"].String() = guestAccountID;
  126. toSend["accountCookie"].String() = getHostAccountCookie();
  127. sendMessage(connection, toSend);
  128. proxyConnections[guestAccountID] = connection;
  129. owner.onNewConnection(connection);
  130. }
  131. }
  132. JsonNode GlobalLobbyProcessor::getHostModList() const
  133. {
  134. ModCompatibilityInfo info;
  135. for (auto const & modName : VLC->modh->getActiveMods())
  136. {
  137. if(VLC->modh->getModInfo(modName).affectsGameplay())
  138. info[modName] = VLC->modh->getModInfo(modName).getVerificationInfo();
  139. }
  140. return ModVerificationInfo::jsonSerializeList(info);
  141. }
  142. void GlobalLobbyProcessor::sendGameStarted()
  143. {
  144. JsonNode toSend;
  145. toSend["type"].String() = "gameStarted";
  146. sendMessage(controlConnection, toSend);
  147. }
  148. void GlobalLobbyProcessor::sendChangeRoomDescription(const std::string & description)
  149. {
  150. JsonNode toSend;
  151. toSend["type"].String() = "changeRoomDescription";
  152. toSend["description"].String() = description;
  153. sendMessage(controlConnection, toSend);
  154. }
  155. void GlobalLobbyProcessor::sendMessage(const NetworkConnectionPtr & targetConnection, const JsonNode & toSend)
  156. {
  157. assert(JsonUtils::validate(toSend, "vcmi:lobbyProtocol/" + toSend["type"].String(), toSend["type"].String() + " pack"));
  158. targetConnection->sendPacket(toSend.toBytes());
  159. }
  160. //FIXME: consider whether these methods should be replaced with some other way to define our account ID / account cookie
  161. static const std::string & getServerHost()
  162. {
  163. return settings["lobby"]["hostname"].String();
  164. }
  165. const std::string & GlobalLobbyProcessor::getHostAccountID() const
  166. {
  167. return persistentStorage["lobby"][getServerHost()]["accountID"].String();
  168. }
  169. const std::string & GlobalLobbyProcessor::getHostAccountCookie() const
  170. {
  171. return persistentStorage["lobby"][getServerHost()]["accountCookie"].String();
  172. }
  173. const std::string & GlobalLobbyProcessor::getHostAccountDisplayName() const
  174. {
  175. return persistentStorage["lobby"][getServerHost()]["displayName"].String();
  176. }