NetPacksLobbyServer.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  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/entities/faction/CTownHandler.h"
  18. #include "../lib/filesystem/Filesystem.h"
  19. #include "../lib/gameState/CGameState.h"
  20. #include "../lib/mapping/CMapInfo.h"
  21. #include "../lib/serializer/Connection.h"
  22. void ClientPermissionsCheckerNetPackVisitor::visitForLobby(CPackForLobby & pack)
  23. {
  24. if(pack.isForServer())
  25. {
  26. result = srv.isClientHost(connection->connectionID);
  27. }
  28. }
  29. void ApplyOnServerAfterAnnounceNetPackVisitor::visitForLobby(CPackForLobby & pack)
  30. {
  31. // Propagate options after every CLobbyPackToServer
  32. if(pack.isForServer())
  33. {
  34. srv.updateAndPropagateLobbyState();
  35. }
  36. }
  37. void ClientPermissionsCheckerNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack)
  38. {
  39. result = srv.getState() == EServerState::LOBBY;
  40. }
  41. void ApplyOnServerNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack)
  42. {
  43. auto compatibleVersion = std::min(pack.version, ESerializationVersion::CURRENT);
  44. connection->setSerializationVersion(compatibleVersion);
  45. srv.clientConnected(connection, pack.names, pack.uuid, pack.mode);
  46. // Server need to pass some data to newly connected client
  47. pack.clientId = connection->connectionID;
  48. pack.mode = srv.si->mode;
  49. pack.hostClientId = srv.hostClientId;
  50. pack.version = compatibleVersion;
  51. result = true;
  52. }
  53. void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack)
  54. {
  55. srv.updateAndPropagateLobbyState();
  56. }
  57. void ClientPermissionsCheckerNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
  58. {
  59. if(pack.clientId != connection->connectionID)
  60. {
  61. result = false;
  62. return;
  63. }
  64. if(pack.shutdownServer)
  65. {
  66. if(!srv.wasStartedByClient())
  67. {
  68. result = false;
  69. return;
  70. }
  71. if(connection->connectionID != srv.hostClientId)
  72. {
  73. result = false;
  74. return;
  75. }
  76. }
  77. result = true;
  78. }
  79. void ApplyOnServerNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
  80. {
  81. connection->getConnection()->close();
  82. srv.clientDisconnected(connection);
  83. result = true;
  84. }
  85. void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
  86. {
  87. srv.updateAndPropagateLobbyState();
  88. }
  89. void ClientPermissionsCheckerNetPackVisitor::visitLobbyChatMessage(LobbyChatMessage & pack)
  90. {
  91. result = true;
  92. }
  93. void ApplyOnServerNetPackVisitor::visitLobbySetMap(LobbySetMap & pack)
  94. {
  95. if(srv.getState() != EServerState::LOBBY)
  96. {
  97. result = false;
  98. return;
  99. }
  100. srv.updateStartInfoOnMapChange(pack.mapInfo, pack.mapGenOpts);
  101. result = true;
  102. }
  103. void ApplyOnServerNetPackVisitor::visitLobbySetCampaign(LobbySetCampaign & pack)
  104. {
  105. srv.si->mapname = pack.ourCampaign->getFilename();
  106. srv.si->mode = EStartMode::CAMPAIGN;
  107. srv.si->campState = pack.ourCampaign;
  108. srv.si->turnTimerInfo = TurnTimerInfo{};
  109. bool isCurrentMapConquerable = pack.ourCampaign->currentScenario() && pack.ourCampaign->isAvailable(*pack.ourCampaign->currentScenario());
  110. auto scenarios = pack.ourCampaign->allScenarios();
  111. for(auto scenarioID : boost::adaptors::reverse(scenarios)) // reverse -> on multiple scenario selection set lowest id at the end
  112. {
  113. if(pack.ourCampaign->isAvailable(scenarioID))
  114. {
  115. if(!isCurrentMapConquerable || (isCurrentMapConquerable && scenarioID == *pack.ourCampaign->currentScenario()))
  116. {
  117. srv.setCampaignMap(scenarioID);
  118. }
  119. }
  120. }
  121. result = true;
  122. }
  123. void ApplyOnServerNetPackVisitor::visitLobbySetCampaignMap(LobbySetCampaignMap & pack)
  124. {
  125. srv.setCampaignMap(pack.mapId);
  126. result = true;
  127. }
  128. void ApplyOnServerNetPackVisitor::visitLobbySetCampaignBonus(LobbySetCampaignBonus & pack)
  129. {
  130. srv.setCampaignBonus(pack.bonusId);
  131. result = true;
  132. }
  133. void ClientPermissionsCheckerNetPackVisitor::visitLobbyGuiAction(LobbyGuiAction & pack)
  134. {
  135. result = srv.isClientHost(connection->connectionID);
  136. }
  137. void ClientPermissionsCheckerNetPackVisitor::visitLobbyRestartGame(LobbyRestartGame & pack)
  138. {
  139. result = srv.isClientHost(connection->connectionID);
  140. }
  141. void ApplyOnServerNetPackVisitor::visitLobbyRestartGame(LobbyRestartGame & pack)
  142. {
  143. srv.prepareToRestart();
  144. result = true;
  145. }
  146. void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyRestartGame(LobbyRestartGame & pack)
  147. {
  148. for(const auto & connection : srv.activeConnections)
  149. connection->enterLobbyConnectionMode();
  150. }
  151. void ClientPermissionsCheckerNetPackVisitor::visitLobbyPrepareStartGame(LobbyPrepareStartGame & pack)
  152. {
  153. result = srv.isClientHost(connection->connectionID);
  154. }
  155. void ClientPermissionsCheckerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
  156. {
  157. result = srv.isClientHost(connection->connectionID);
  158. }
  159. void ApplyOnServerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
  160. {
  161. try
  162. {
  163. srv.verifyStateBeforeStart(true);
  164. }
  165. catch(const std::exception &)
  166. {
  167. result = false;
  168. return;
  169. }
  170. // Server will prepare gamestate and we announce StartInfo to clients
  171. if(!srv.prepareToStartGame())
  172. {
  173. result = false;
  174. return;
  175. }
  176. pack.initializedStartInfo = std::make_shared<StartInfo>(*srv.gh->gameState().getInitialStartInfo());
  177. pack.initializedGameState = srv.gh->gs;
  178. result = true;
  179. }
  180. void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
  181. {
  182. if(pack.clientId == -1) //do not restart game for single client only
  183. srv.startGameImmediately();
  184. else
  185. {
  186. for(const auto & connection : srv.activeConnections)
  187. {
  188. if(connection->connectionID == pack.clientId)
  189. {
  190. connection->setCallback(srv.gh->gameInfo());
  191. srv.reconnectPlayer(pack.clientId);
  192. }
  193. }
  194. }
  195. }
  196. void ClientPermissionsCheckerNetPackVisitor::visitLobbyChangeHost(LobbyChangeHost & pack)
  197. {
  198. result = srv.isClientHost(connection->connectionID);
  199. }
  200. void ApplyOnServerNetPackVisitor::visitLobbyChangeHost(LobbyChangeHost & pack)
  201. {
  202. result = true;
  203. }
  204. void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyChangeHost(LobbyChangeHost & pack)
  205. {
  206. auto result = srv.passHost(pack.newHostConnectionId);
  207. if(!result)
  208. {
  209. logGlobal->error("passHost returned false. What does it mean?");
  210. }
  211. }
  212. void ClientPermissionsCheckerNetPackVisitor::visitLobbyChangePlayerOption(LobbyChangePlayerOption & pack)
  213. {
  214. if(srv.isClientHost(connection->connectionID))
  215. {
  216. result = true;
  217. return;
  218. }
  219. if(vstd::contains(srv.getAllClientPlayers(connection->connectionID), pack.color))
  220. {
  221. result = true;
  222. return;
  223. }
  224. result = false;
  225. }
  226. void ApplyOnServerNetPackVisitor::visitLobbyChangePlayerOption(LobbyChangePlayerOption & pack)
  227. {
  228. switch(pack.what)
  229. {
  230. case LobbyChangePlayerOption::TOWN_ID:
  231. srv.optionSetCastle(pack.color, FactionID(pack.value));
  232. break;
  233. case LobbyChangePlayerOption::TOWN:
  234. srv.optionNextCastle(pack.color, pack.value);
  235. break;
  236. case LobbyChangePlayerOption::HERO_ID:
  237. srv.optionSetHero(pack.color, HeroTypeID(pack.value));
  238. break;
  239. case LobbyChangePlayerOption::HERO:
  240. srv.optionNextHero(pack.color, pack.value);
  241. break;
  242. case LobbyChangePlayerOption::BONUS_ID:
  243. srv.optionSetBonus(pack.color, static_cast<PlayerStartingBonus>(pack.value));
  244. break;
  245. case LobbyChangePlayerOption::BONUS:
  246. srv.optionNextBonus(pack.color, pack.value);
  247. break;
  248. }
  249. result = true;
  250. }
  251. void ApplyOnServerNetPackVisitor::visitLobbySetPlayer(LobbySetPlayer & pack)
  252. {
  253. srv.setPlayer(pack.clickedColor);
  254. result = true;
  255. }
  256. void ApplyOnServerNetPackVisitor::visitLobbySetPlayerName(LobbySetPlayerName & pack)
  257. {
  258. srv.setPlayerName(pack.color, pack.name);
  259. result = true;
  260. }
  261. void ApplyOnServerNetPackVisitor::visitLobbySetPlayerHandicap(LobbySetPlayerHandicap & pack)
  262. {
  263. srv.setPlayerHandicap(pack.color, pack.handicap);
  264. result = true;
  265. }
  266. void ApplyOnServerNetPackVisitor::visitLobbySetSimturns(LobbySetSimturns & pack)
  267. {
  268. srv.si->simturnsInfo = pack.simturnsInfo;
  269. result = true;
  270. }
  271. void ApplyOnServerNetPackVisitor::visitLobbySetTurnTime(LobbySetTurnTime & pack)
  272. {
  273. srv.si->turnTimerInfo = pack.turnTimerInfo;
  274. result = true;
  275. }
  276. void ApplyOnServerNetPackVisitor::visitLobbySetExtraOptions(LobbySetExtraOptions & pack)
  277. {
  278. srv.si->extraOptionsInfo = pack.extraOptionsInfo;
  279. result = true;
  280. }
  281. void ApplyOnServerNetPackVisitor::visitLobbySetDifficulty(LobbySetDifficulty & pack)
  282. {
  283. srv.si->difficulty = std::clamp<uint8_t>(pack.difficulty, 0, 4);
  284. result = true;
  285. }
  286. void ApplyOnServerNetPackVisitor::visitLobbyForceSetPlayer(LobbyForceSetPlayer & pack)
  287. {
  288. srv.si->playerInfos[pack.targetPlayerColor].connectedPlayerIDs.insert(pack.targetConnectedPlayer);
  289. result = true;
  290. }
  291. void ClientPermissionsCheckerNetPackVisitor::visitLobbyPvPAction(LobbyPvPAction & pack)
  292. {
  293. result = true;
  294. }
  295. void ApplyOnServerNetPackVisitor::visitLobbyPvPAction(LobbyPvPAction & pack)
  296. {
  297. std::vector<FactionID> allowedTowns;
  298. for (auto const & factionID : LIBRARY->townh->getDefaultAllowed())
  299. if(std::find(pack.bannedTowns.begin(), pack.bannedTowns.end(), factionID) == pack.bannedTowns.end())
  300. allowedTowns.push_back(factionID);
  301. std::vector<FactionID> randomFaction1;
  302. std::sample(allowedTowns.begin(), allowedTowns.end(), std::back_inserter(randomFaction1), 1, std::mt19937{std::random_device{}()});
  303. std::vector<FactionID> randomFaction2;
  304. std::sample(allowedTowns.begin(), allowedTowns.end(), std::back_inserter(randomFaction2), 1, std::mt19937{std::random_device{}()});
  305. MetaString txt;
  306. switch(pack.action) {
  307. case LobbyPvPAction::COIN:
  308. txt.appendTextID("vcmi.lobby.pvp.coin.hover");
  309. txt.appendRawString(" - " + std::to_string(CRandomGenerator::getDefault().nextInt(1)));
  310. srv.announceTxt(txt);
  311. break;
  312. case LobbyPvPAction::RANDOM_TOWN:
  313. if(!allowedTowns.size())
  314. break;
  315. txt.appendTextID("core.overview.3");
  316. txt.appendRawString(" - ");
  317. txt.appendTextID(LIBRARY->townh->getById(randomFaction1[0])->getNameTextID());
  318. srv.announceTxt(txt);
  319. break;
  320. case LobbyPvPAction::RANDOM_TOWN_VS:
  321. if(!allowedTowns.size())
  322. break;
  323. txt.appendTextID("core.overview.3");
  324. txt.appendRawString(" - ");
  325. txt.appendTextID(LIBRARY->townh->getById(randomFaction1[0])->getNameTextID());
  326. txt.appendRawString(" ");
  327. txt.appendTextID("vcmi.lobby.pvp.versus");
  328. txt.appendRawString(" ");
  329. txt.appendTextID(LIBRARY->townh->getById(randomFaction2[0])->getNameTextID());
  330. srv.announceTxt(txt);
  331. break;
  332. }
  333. result = true;
  334. }
  335. void ClientPermissionsCheckerNetPackVisitor::visitLobbyDelete(LobbyDelete & pack)
  336. {
  337. result = srv.isClientHost(connection->connectionID);
  338. }
  339. void ApplyOnServerNetPackVisitor::visitLobbyDelete(LobbyDelete & pack)
  340. {
  341. if(pack.type == LobbyDelete::EType::SAVEGAME || pack.type == LobbyDelete::EType::RANDOMMAP)
  342. {
  343. auto res = ResourcePath(pack.name, pack.type == LobbyDelete::EType::SAVEGAME ? EResType::SAVEGAME : EResType::MAP);
  344. auto name = CResourceHandler::get()->getResourceName(res);
  345. if (!name)
  346. {
  347. logGlobal->error("Failed to find resource with name '%s'", res.getOriginalName());
  348. return;
  349. }
  350. boost::system::error_code ec;
  351. auto file = boost::filesystem::canonical(*name, ec);
  352. if (ec)
  353. {
  354. logGlobal->error("Failed to delete file '%s'. Reason: %s", res.getOriginalName(), ec.message());
  355. }
  356. else
  357. {
  358. boost::filesystem::remove(file);
  359. if(boost::filesystem::is_empty(file.parent_path()))
  360. boost::filesystem::remove(file.parent_path());
  361. }
  362. }
  363. else if(pack.type == LobbyDelete::EType::SAVEGAME_FOLDER)
  364. {
  365. auto res = ResourcePath("Saves/" + pack.name, EResType::DIRECTORY);
  366. auto name = CResourceHandler::get()->getResourceName(res);
  367. if (!name)
  368. {
  369. logGlobal->error("Failed to find folder with name '%s'", res.getOriginalName());
  370. return;
  371. }
  372. boost::system::error_code ec;
  373. auto folder = boost::filesystem::canonical(*name);
  374. if (ec)
  375. {
  376. logGlobal->error("Failed to delete folder '%s'. Reason: %s", res.getOriginalName(), ec.message());
  377. }
  378. else
  379. {
  380. boost::filesystem::remove_all(folder);
  381. }
  382. }
  383. LobbyUpdateState lus;
  384. lus.state = srv;
  385. lus.refreshList = true;
  386. srv.announcePack(lus);
  387. }