GlobalLobbyClient.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /*
  2. * GlobalLobbyClient.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 "GlobalLobbyClient.h"
  12. #include "GlobalLobbyLoginWindow.h"
  13. #include "GlobalLobbyWindow.h"
  14. #include "../gui/CGuiHandler.h"
  15. #include "../gui/WindowHandler.h"
  16. #include "../windows/InfoWindows.h"
  17. #include "../CServerHandler.h"
  18. #include "../../lib/CConfigHandler.h"
  19. #include "../../lib/MetaString.h"
  20. #include "../../lib/TextOperations.h"
  21. GlobalLobbyClient::GlobalLobbyClient() = default;
  22. GlobalLobbyClient::~GlobalLobbyClient() = default;
  23. static std::string getCurrentTimeFormatted(int timeOffsetSeconds = 0)
  24. {
  25. // FIXME: better/unified way to format date
  26. auto timeNowChrono = std::chrono::system_clock::now();
  27. timeNowChrono += std::chrono::seconds(timeOffsetSeconds);
  28. return TextOperations::getFormattedTimeLocal(std::chrono::system_clock::to_time_t(timeNowChrono));
  29. }
  30. void GlobalLobbyClient::onPacketReceived(const std::shared_ptr<INetworkConnection> &, const std::vector<uint8_t> & message)
  31. {
  32. boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
  33. JsonNode json(message.data(), message.size());
  34. if(json["type"].String() == "accountCreated")
  35. return receiveAccountCreated(json);
  36. if(json["type"].String() == "loginFailed")
  37. return receiveLoginFailed(json);
  38. if(json["type"].String() == "loginSuccess")
  39. return receiveLoginSuccess(json);
  40. if(json["type"].String() == "chatHistory")
  41. return receiveChatHistory(json);
  42. if(json["type"].String() == "chatMessage")
  43. return receiveChatMessage(json);
  44. if(json["type"].String() == "activeAccounts")
  45. return receiveActiveAccounts(json);
  46. if(json["type"].String() == "activeGameRooms")
  47. return receiveActiveGameRooms(json);
  48. if(json["type"].String() == "joinRoomSuccess")
  49. return receiveJoinRoomSuccess(json);
  50. throw std::runtime_error("Received unexpected message from lobby server: " + json["type"].String());
  51. }
  52. void GlobalLobbyClient::receiveAccountCreated(const JsonNode & json)
  53. {
  54. auto loginWindowPtr = loginWindow.lock();
  55. if(!loginWindowPtr || !GH.windows().topWindow<GlobalLobbyLoginWindow>())
  56. throw std::runtime_error("lobby connection finished without active login window!");
  57. {
  58. Settings configID = settings.write["lobby"]["accountID"];
  59. configID->String() = json["accountID"].String();
  60. Settings configName = settings.write["lobby"]["displayName"];
  61. configName->String() = json["displayName"].String();
  62. Settings configCookie = settings.write["lobby"]["accountCookie"];
  63. configCookie->String() = json["accountCookie"].String();
  64. }
  65. sendClientLogin();
  66. }
  67. void GlobalLobbyClient::receiveLoginFailed(const JsonNode & json)
  68. {
  69. auto loginWindowPtr = loginWindow.lock();
  70. if(!loginWindowPtr || !GH.windows().topWindow<GlobalLobbyLoginWindow>())
  71. throw std::runtime_error("lobby connection finished without active login window!");
  72. loginWindowPtr->onConnectionFailed(json["reason"].String());
  73. }
  74. void GlobalLobbyClient::receiveLoginSuccess(const JsonNode & json)
  75. {
  76. {
  77. Settings configCookie = settings.write["lobby"]["accountCookie"];
  78. configCookie->String() = json["accountCookie"].String();
  79. Settings configName = settings.write["lobby"]["displayName"];
  80. configName->String() = json["displayName"].String();
  81. }
  82. auto loginWindowPtr = loginWindow.lock();
  83. if(!loginWindowPtr || !GH.windows().topWindow<GlobalLobbyLoginWindow>())
  84. throw std::runtime_error("lobby connection finished without active login window!");
  85. loginWindowPtr->onConnectionSuccess();
  86. }
  87. void GlobalLobbyClient::receiveChatHistory(const JsonNode & json)
  88. {
  89. for(const auto & entry : json["messages"].Vector())
  90. {
  91. std::string accountID = entry["accountID"].String();
  92. std::string displayName = entry["displayName"].String();
  93. std::string messageText = entry["messageText"].String();
  94. int ageSeconds = entry["ageSeconds"].Integer();
  95. std::string timeFormatted = getCurrentTimeFormatted(-ageSeconds);
  96. auto lobbyWindowPtr = lobbyWindow.lock();
  97. if(lobbyWindowPtr)
  98. lobbyWindowPtr->onGameChatMessage(displayName, messageText, timeFormatted);
  99. }
  100. }
  101. void GlobalLobbyClient::receiveChatMessage(const JsonNode & json)
  102. {
  103. std::string accountID = json["accountID"].String();
  104. std::string displayName = json["displayName"].String();
  105. std::string messageText = json["messageText"].String();
  106. std::string timeFormatted = getCurrentTimeFormatted();
  107. auto lobbyWindowPtr = lobbyWindow.lock();
  108. if(lobbyWindowPtr)
  109. lobbyWindowPtr->onGameChatMessage(displayName, messageText, timeFormatted);
  110. }
  111. void GlobalLobbyClient::receiveActiveAccounts(const JsonNode & json)
  112. {
  113. activeAccounts.clear();
  114. for (auto const & jsonEntry : json["accounts"].Vector())
  115. {
  116. GlobalLobbyAccount account;
  117. account.accountID = jsonEntry["accountID"].String();
  118. account.displayName = jsonEntry["displayName"].String();
  119. account.status = jsonEntry["status"].String();
  120. activeAccounts.push_back(account);
  121. }
  122. auto lobbyWindowPtr = lobbyWindow.lock();
  123. if(lobbyWindowPtr)
  124. lobbyWindowPtr->onActiveAccounts(activeAccounts);
  125. }
  126. void GlobalLobbyClient::receiveActiveGameRooms(const JsonNode & json)
  127. {
  128. activeRooms.clear();
  129. for (auto const & jsonEntry : json["gameRooms"].Vector())
  130. {
  131. GlobalLobbyRoom room;
  132. room.gameRoomID = jsonEntry["gameRoomID"].String();
  133. room.hostAccountID = jsonEntry["hostAccountID"].String();
  134. room.hostAccountDisplayName = jsonEntry["hostAccountDisplayName"].String();
  135. room.description = jsonEntry["description"].String();
  136. // room.status = jsonEntry["status"].String();
  137. room.playersCount = jsonEntry["playersCount"].Integer();
  138. room.playersLimit = jsonEntry["playersLimit"].Integer();
  139. activeRooms.push_back(room);
  140. }
  141. auto lobbyWindowPtr = lobbyWindow.lock();
  142. if(lobbyWindowPtr)
  143. lobbyWindowPtr->onActiveRooms(activeRooms);
  144. }
  145. void GlobalLobbyClient::receiveJoinRoomSuccess(const JsonNode & json)
  146. {
  147. // TODO: store "gameRoomID" field and use it for future queries
  148. }
  149. void GlobalLobbyClient::onConnectionEstablished(const std::shared_ptr<INetworkConnection> & connection)
  150. {
  151. networkConnection = connection;
  152. JsonNode toSend;
  153. std::string accountID = settings["lobby"]["accountID"].String();
  154. if(accountID.empty())
  155. sendClientRegister();
  156. else
  157. sendClientLogin();
  158. }
  159. void GlobalLobbyClient::sendClientRegister()
  160. {
  161. JsonNode toSend;
  162. toSend["type"].String() = "clientRegister";
  163. toSend["displayName"] = settings["lobby"]["displayName"];
  164. sendMessage(toSend);
  165. }
  166. void GlobalLobbyClient::sendClientLogin()
  167. {
  168. JsonNode toSend;
  169. toSend["type"].String() = "clientLogin";
  170. toSend["accountID"] = settings["lobby"]["accountID"];
  171. toSend["accountCookie"] = settings["lobby"]["accountCookie"];
  172. sendMessage(toSend);
  173. }
  174. void GlobalLobbyClient::onConnectionFailed(const std::string & errorMessage)
  175. {
  176. auto loginWindowPtr = loginWindow.lock();
  177. if(!loginWindowPtr || !GH.windows().topWindow<GlobalLobbyLoginWindow>())
  178. throw std::runtime_error("lobby connection failed without active login window!");
  179. logGlobal->warn("Connection to game lobby failed! Reason: %s", errorMessage);
  180. loginWindowPtr->onConnectionFailed(errorMessage);
  181. }
  182. void GlobalLobbyClient::onDisconnected(const std::shared_ptr<INetworkConnection> & connection)
  183. {
  184. assert(connection == networkConnection);
  185. networkConnection.reset();
  186. GH.windows().popWindows(1);
  187. CInfoWindow::showInfoDialog("Connection to game lobby was lost!", {});
  188. }
  189. void GlobalLobbyClient::sendMessage(const JsonNode & data)
  190. {
  191. std::string payloadString = data.toJson(true);
  192. // FIXME: find better approach
  193. uint8_t * payloadBegin = reinterpret_cast<uint8_t *>(payloadString.data());
  194. uint8_t * payloadEnd = payloadBegin + payloadString.size();
  195. std::vector<uint8_t> payloadBuffer(payloadBegin, payloadEnd);
  196. networkConnection->sendPacket(payloadBuffer);
  197. }
  198. void GlobalLobbyClient::sendOpenPublicRoom()
  199. {
  200. JsonNode toSend;
  201. toSend["type"].String() = "openGameRoom";
  202. toSend["hostAccountID"] = settings["lobby"]["accountID"];
  203. toSend["roomType"].String() = "public";
  204. sendMessage(toSend);
  205. }
  206. void GlobalLobbyClient::sendOpenPrivateRoom()
  207. {
  208. JsonNode toSend;
  209. toSend["type"].String() = "openGameRoom";
  210. toSend["hostAccountID"] = settings["lobby"]["accountID"];
  211. toSend["roomType"].String() = "private";
  212. sendMessage(toSend);
  213. }
  214. void GlobalLobbyClient::connect()
  215. {
  216. std::string hostname = settings["lobby"]["hostname"].String();
  217. int16_t port = settings["lobby"]["port"].Integer();
  218. CSH->networkHandler->connectToRemote(*this, hostname, port);
  219. }
  220. bool GlobalLobbyClient::isConnected()
  221. {
  222. return networkConnection != nullptr;
  223. }
  224. std::shared_ptr<GlobalLobbyLoginWindow> GlobalLobbyClient::createLoginWindow()
  225. {
  226. auto loginWindowPtr = loginWindow.lock();
  227. if(loginWindowPtr)
  228. return loginWindowPtr;
  229. auto loginWindowNew = std::make_shared<GlobalLobbyLoginWindow>();
  230. loginWindow = loginWindowNew;
  231. return loginWindowNew;
  232. }
  233. std::shared_ptr<GlobalLobbyWindow> GlobalLobbyClient::createLobbyWindow()
  234. {
  235. auto lobbyWindowPtr = lobbyWindow.lock();
  236. if(lobbyWindowPtr)
  237. return lobbyWindowPtr;
  238. lobbyWindowPtr = std::make_shared<GlobalLobbyWindow>();
  239. lobbyWindow = lobbyWindowPtr;
  240. lobbyWindowLock = lobbyWindowPtr;
  241. return lobbyWindowPtr;
  242. }
  243. const std::vector<GlobalLobbyAccount> & GlobalLobbyClient::getActiveAccounts() const
  244. {
  245. return activeAccounts;
  246. }
  247. const std::vector<GlobalLobbyRoom> & GlobalLobbyClient::getActiveRooms() const
  248. {
  249. return activeRooms;
  250. }
  251. void GlobalLobbyClient::activateInterface()
  252. {
  253. if (!GH.windows().findWindows<GlobalLobbyWindow>().empty())
  254. return;
  255. if (!GH.windows().findWindows<GlobalLobbyLoginWindow>().empty())
  256. return;
  257. if (isConnected())
  258. GH.windows().pushWindow(createLobbyWindow());
  259. else
  260. GH.windows().pushWindow(createLoginWindow());
  261. }