NetPacksLobbyServer.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. /*
  2. * NetPacksLobbyServer.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 "LobbyNetPackVisitors.h"
  12. #include "CVCMIServer.h"
  13. #include "CGameHandler.h"
  14. #include "../lib/StartInfo.h"
  15. #include "../lib/CRandomGenerator.h"
  16. #include "../lib/campaign/CampaignState.h"
  17. #include "../lib/serializer/Connection.h"
  18. #include "../lib/mapping/CMapInfo.h"
  19. #include "../lib/mapping/CMapHeader.h"
  20. #include "../lib/CTownHandler.h"
  21. void ClientPermissionsCheckerNetPackVisitor::visitForLobby(CPackForLobby & pack)
  22. {
  23. if(pack.isForServer())
  24. {
  25. result = srv.isClientHost(pack.c->connectionID);
  26. }
  27. }
  28. void ApplyOnServerAfterAnnounceNetPackVisitor::visitForLobby(CPackForLobby & pack)
  29. {
  30. // Propogate options after every CLobbyPackToServer
  31. if(pack.isForServer())
  32. {
  33. srv.updateAndPropagateLobbyState();
  34. }
  35. }
  36. void ClientPermissionsCheckerNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack)
  37. {
  38. result = srv.getState() == EServerState::LOBBY;
  39. }
  40. void ApplyOnServerNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack)
  41. {
  42. auto compatibleVersion = std::min(pack.version, ESerializationVersion::CURRENT);
  43. pack.c->setSerializationVersion(compatibleVersion);
  44. srv.clientConnected(pack.c, pack.names, pack.uuid, pack.mode);
  45. // Server need to pass some data to newly connected client
  46. pack.clientId = pack.c->connectionID;
  47. pack.mode = srv.si->mode;
  48. pack.hostClientId = srv.hostClientId;
  49. pack.version = compatibleVersion;
  50. result = true;
  51. }
  52. void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack)
  53. {
  54. // FIXME: we need to avoid senting something to client that not yet get answer for LobbyClientConnected
  55. // Until UUID set we only pass LobbyClientConnected to this client
  56. pack.c->uuid = pack.uuid;
  57. srv.updateAndPropagateLobbyState();
  58. // FIXME: what is this??? We do NOT support reconnection into ongoing game - at the very least queries and battles are NOT serialized
  59. // if(srv.getState() == EServerState::GAMEPLAY)
  60. // {
  61. // //immediately start game
  62. // std::unique_ptr<LobbyStartGame> startGameForReconnectedPlayer(new LobbyStartGame);
  63. // startGameForReconnectedPlayer->initializedStartInfo = srv.si;
  64. // startGameForReconnectedPlayer->initializedGameState = srv.gh->gameState();
  65. // startGameForReconnectedPlayer->clientId = pack.c->connectionID;
  66. // srv.announcePack(std::move(startGameForReconnectedPlayer));
  67. // }
  68. }
  69. void ClientPermissionsCheckerNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
  70. {
  71. if(pack.clientId != pack.c->connectionID)
  72. {
  73. result = false;
  74. return;
  75. }
  76. if(pack.shutdownServer)
  77. {
  78. if(!srv.wasStartedByClient())
  79. {
  80. result = false;
  81. return;
  82. }
  83. if(pack.c->connectionID != srv.hostClientId)
  84. {
  85. result = false;
  86. return;
  87. }
  88. }
  89. result = true;
  90. }
  91. void ApplyOnServerNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
  92. {
  93. srv.clientDisconnected(pack.c);
  94. result = true;
  95. }
  96. void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
  97. {
  98. if(pack.shutdownServer)
  99. {
  100. logNetwork->info("Client requested shutdown, server will close itself...");
  101. srv.setState(EServerState::SHUTDOWN);
  102. return;
  103. }
  104. else if(srv.activeConnections.empty())
  105. {
  106. logNetwork->error("Last connection lost, server will close itself...");
  107. srv.setState(EServerState::SHUTDOWN);
  108. }
  109. else if(pack.c->connectionID == srv.hostClientId)
  110. {
  111. auto ph = std::make_unique<LobbyChangeHost>();
  112. auto newHost = srv.activeConnections.front();
  113. ph->newHostConnectionId = newHost->connectionID;
  114. srv.announcePack(std::move(ph));
  115. }
  116. srv.updateAndPropagateLobbyState();
  117. // if(srv.getState() != EServerState::SHUTDOWN && srv.remoteConnections.count(pack.c))
  118. // {
  119. // srv.remoteConnections -= pack.c;
  120. // srv.connectToRemote();
  121. // }
  122. }
  123. void ClientPermissionsCheckerNetPackVisitor::visitLobbyChatMessage(LobbyChatMessage & pack)
  124. {
  125. result = true;
  126. }
  127. void ApplyOnServerNetPackVisitor::visitLobbySetMap(LobbySetMap & pack)
  128. {
  129. if(srv.getState() != EServerState::LOBBY)
  130. {
  131. result = false;
  132. return;
  133. }
  134. srv.updateStartInfoOnMapChange(pack.mapInfo, pack.mapGenOpts);
  135. result = true;
  136. }
  137. void ApplyOnServerNetPackVisitor::visitLobbySetCampaign(LobbySetCampaign & pack)
  138. {
  139. srv.si->mapname = pack.ourCampaign->getFilename();
  140. srv.si->mode = EStartMode::CAMPAIGN;
  141. srv.si->campState = pack.ourCampaign;
  142. srv.si->turnTimerInfo = TurnTimerInfo{};
  143. bool isCurrentMapConquerable = pack.ourCampaign->currentScenario() && pack.ourCampaign->isAvailable(*pack.ourCampaign->currentScenario());
  144. for(auto scenarioID : pack.ourCampaign->allScenarios())
  145. {
  146. if(pack.ourCampaign->isAvailable(scenarioID))
  147. {
  148. if(!isCurrentMapConquerable || (isCurrentMapConquerable && scenarioID == *pack.ourCampaign->currentScenario()))
  149. {
  150. srv.setCampaignMap(scenarioID);
  151. }
  152. }
  153. }
  154. result = true;
  155. }
  156. void ApplyOnServerNetPackVisitor::visitLobbySetCampaignMap(LobbySetCampaignMap & pack)
  157. {
  158. srv.setCampaignMap(pack.mapId);
  159. result = true;
  160. }
  161. void ApplyOnServerNetPackVisitor::visitLobbySetCampaignBonus(LobbySetCampaignBonus & pack)
  162. {
  163. srv.setCampaignBonus(pack.bonusId);
  164. result = true;
  165. }
  166. void ClientPermissionsCheckerNetPackVisitor::visitLobbyGuiAction(LobbyGuiAction & pack)
  167. {
  168. result = srv.isClientHost(pack.c->connectionID);
  169. }
  170. void ClientPermissionsCheckerNetPackVisitor::visitLobbyRestartGame(LobbyRestartGame & pack)
  171. {
  172. result = srv.isClientHost(pack.c->connectionID);
  173. }
  174. void ApplyOnServerNetPackVisitor::visitLobbyRestartGame(LobbyRestartGame & pack)
  175. {
  176. srv.prepareToRestart();
  177. result = true;
  178. }
  179. void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyRestartGame(LobbyRestartGame & pack)
  180. {
  181. for(const auto & connection : srv.activeConnections)
  182. connection->enterLobbyConnectionMode();
  183. }
  184. void ClientPermissionsCheckerNetPackVisitor::visitLobbyPrepareStartGame(LobbyPrepareStartGame & pack)
  185. {
  186. result = srv.isClientHost(pack.c->connectionID);
  187. }
  188. void ClientPermissionsCheckerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
  189. {
  190. result = srv.isClientHost(pack.c->connectionID);
  191. }
  192. void ApplyOnServerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
  193. {
  194. try
  195. {
  196. srv.verifyStateBeforeStart(true);
  197. }
  198. catch(...)
  199. {
  200. result = false;
  201. return;
  202. }
  203. // Server will prepare gamestate and we announce StartInfo to clients
  204. if(!srv.prepareToStartGame())
  205. {
  206. result = false;
  207. return;
  208. }
  209. pack.initializedStartInfo = std::make_shared<StartInfo>(*srv.gh->getStartInfo(true));
  210. pack.initializedGameState = srv.gh->gameState();
  211. result = true;
  212. }
  213. void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
  214. {
  215. if(pack.clientId == -1) //do not restart game for single client only
  216. srv.startGameImmediately();
  217. else
  218. {
  219. for(const auto & connection : srv.activeConnections)
  220. {
  221. if(connection->connectionID == pack.clientId)
  222. {
  223. connection->enterGameplayConnectionMode(srv.gh->gameState());
  224. srv.reconnectPlayer(pack.clientId);
  225. }
  226. }
  227. }
  228. }
  229. void ClientPermissionsCheckerNetPackVisitor::visitLobbyChangeHost(LobbyChangeHost & pack)
  230. {
  231. result = srv.isClientHost(pack.c->connectionID);
  232. }
  233. void ApplyOnServerNetPackVisitor::visitLobbyChangeHost(LobbyChangeHost & pack)
  234. {
  235. result = true;
  236. }
  237. void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyChangeHost(LobbyChangeHost & pack)
  238. {
  239. auto result = srv.passHost(pack.newHostConnectionId);
  240. if(!result)
  241. {
  242. logGlobal->error("passHost returned false. What does it mean?");
  243. }
  244. }
  245. void ClientPermissionsCheckerNetPackVisitor::visitLobbyChangePlayerOption(LobbyChangePlayerOption & pack)
  246. {
  247. if(srv.isClientHost(pack.c->connectionID))
  248. {
  249. result = true;
  250. return;
  251. }
  252. if(vstd::contains(srv.getAllClientPlayers(pack.c->connectionID), pack.color))
  253. {
  254. result = true;
  255. return;
  256. }
  257. result = false;
  258. }
  259. void ApplyOnServerNetPackVisitor::visitLobbyChangePlayerOption(LobbyChangePlayerOption & pack)
  260. {
  261. switch(pack.what)
  262. {
  263. case LobbyChangePlayerOption::TOWN_ID:
  264. srv.optionSetCastle(pack.color, FactionID(pack.value));
  265. break;
  266. case LobbyChangePlayerOption::TOWN:
  267. srv.optionNextCastle(pack.color, pack.value);
  268. break;
  269. case LobbyChangePlayerOption::HERO_ID:
  270. srv.optionSetHero(pack.color, HeroTypeID(pack.value));
  271. break;
  272. case LobbyChangePlayerOption::HERO:
  273. srv.optionNextHero(pack.color, pack.value);
  274. break;
  275. case LobbyChangePlayerOption::BONUS_ID:
  276. srv.optionSetBonus(pack.color, PlayerStartingBonus(pack.value));
  277. break;
  278. case LobbyChangePlayerOption::BONUS:
  279. srv.optionNextBonus(pack.color, pack.value);
  280. break;
  281. }
  282. result = true;
  283. }
  284. void ApplyOnServerNetPackVisitor::visitLobbySetPlayer(LobbySetPlayer & pack)
  285. {
  286. srv.setPlayer(pack.clickedColor);
  287. result = true;
  288. }
  289. void ApplyOnServerNetPackVisitor::visitLobbySetPlayerName(LobbySetPlayerName & pack)
  290. {
  291. srv.setPlayerName(pack.color, pack.name);
  292. result = true;
  293. }
  294. void ApplyOnServerNetPackVisitor::visitLobbySetSimturns(LobbySetSimturns & pack)
  295. {
  296. srv.si->simturnsInfo = pack.simturnsInfo;
  297. result = true;
  298. }
  299. void ApplyOnServerNetPackVisitor::visitLobbySetTurnTime(LobbySetTurnTime & pack)
  300. {
  301. srv.si->turnTimerInfo = pack.turnTimerInfo;
  302. result = true;
  303. }
  304. void ApplyOnServerNetPackVisitor::visitLobbySetExtraOptions(LobbySetExtraOptions & pack)
  305. {
  306. srv.si->extraOptionsInfo = pack.extraOptionsInfo;
  307. result = true;
  308. }
  309. void ApplyOnServerNetPackVisitor::visitLobbySetDifficulty(LobbySetDifficulty & pack)
  310. {
  311. srv.si->difficulty = std::clamp<uint8_t>(pack.difficulty, 0, 4);
  312. result = true;
  313. }
  314. void ApplyOnServerNetPackVisitor::visitLobbyForceSetPlayer(LobbyForceSetPlayer & pack)
  315. {
  316. srv.si->playerInfos[pack.targetPlayerColor].connectedPlayerIDs.insert(pack.targetConnectedPlayer);
  317. result = true;
  318. }
  319. void ClientPermissionsCheckerNetPackVisitor::visitLobbyPvPAction(LobbyPvPAction & pack)
  320. {
  321. result = true;
  322. }
  323. void ApplyOnServerNetPackVisitor::visitLobbyPvPAction(LobbyPvPAction & pack)
  324. {
  325. std::vector<FactionID> allowedTowns;
  326. for (auto const & factionID : VLC->townh->getDefaultAllowed())
  327. if(std::find(pack.bannedTowns.begin(), pack.bannedTowns.end(), factionID) == pack.bannedTowns.end())
  328. allowedTowns.push_back(factionID);
  329. std::vector<FactionID> randomFaction1;
  330. std::sample(allowedTowns.begin(), allowedTowns.end(), std::back_inserter(randomFaction1), 1, std::mt19937{std::random_device{}()});
  331. std::vector<FactionID> randomFaction2;
  332. std::sample(allowedTowns.begin(), allowedTowns.end(), std::back_inserter(randomFaction2), 1, std::mt19937{std::random_device{}()});
  333. MetaString txt;
  334. switch(pack.action) {
  335. case LobbyPvPAction::COIN:
  336. txt.appendTextID("vcmi.lobby.pvp.coin.hover");
  337. txt.appendRawString(" - " + std::to_string(std::rand()%2));
  338. srv.announceTxt(txt);
  339. break;
  340. case LobbyPvPAction::RANDOM_TOWN:
  341. if(!allowedTowns.size())
  342. break;
  343. txt.appendTextID("core.overview.3");
  344. txt.appendRawString(" - ");
  345. txt.appendTextID(VLC->townh->getById(randomFaction1[0])->getNameTextID());
  346. srv.announceTxt(txt);
  347. break;
  348. case LobbyPvPAction::RANDOM_TOWN_VS:
  349. if(!allowedTowns.size())
  350. break;
  351. txt.appendTextID("core.overview.3");
  352. txt.appendRawString(" - ");
  353. txt.appendTextID(VLC->townh->getById(randomFaction1[0])->getNameTextID());
  354. txt.appendRawString(" ");
  355. txt.appendTextID("vcmi.lobby.pvp.versus");
  356. txt.appendRawString(" ");
  357. txt.appendTextID(VLC->townh->getById(randomFaction2[0])->getNameTextID());
  358. srv.announceTxt(txt);
  359. break;
  360. }
  361. result = true;
  362. }