AntilagServer.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /*
  2. * AntilagServer.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 "AntilagServer.h"
  12. #include "CServerHandler.h"
  13. #include "Client.h"
  14. #include "GameEngine.h"
  15. #include "../server/CGameHandler.h"
  16. #include "../lib/gameState/CGameState.h"
  17. #include "../lib/mapObjects/CGHeroInstance.h"
  18. #include "../lib/serializer/GameConnection.h"
  19. #include "GameInstance.h"
  20. class DLL_LINKAGE AntilagRollbackNotSupportedException : public std::runtime_error
  21. {
  22. public:
  23. using std::runtime_error::runtime_error;
  24. };
  25. int ConnectionPackWriter::write(const std::byte * data, unsigned size)
  26. {
  27. buffer.insert(buffer.end(), data, data + size);
  28. return size;
  29. }
  30. void AntilagRollbackGeneratorVisitor::visitPackageReceived(PackageReceived & pack)
  31. {
  32. success = true;
  33. // no-op rollback?
  34. }
  35. void AntilagRollbackGeneratorVisitor::visitPackageApplied(PackageApplied & pack)
  36. {
  37. success = true;
  38. // no-op rollback?
  39. }
  40. void AntilagRollbackGeneratorVisitor::visitPlayerBlocked(PlayerBlocked & pack)
  41. {
  42. success = true;
  43. // no-op rollback?
  44. }
  45. void AntilagRollbackGeneratorVisitor::visitHeroVisitCastle(HeroVisitCastle & pack)
  46. {
  47. auto rollbackVisit = std::make_unique<HeroVisitCastle>();
  48. rollbackVisit->startVisit = !pack.startVisit;
  49. rollbackVisit->tid = pack.tid;
  50. rollbackVisit->hid = pack.hid;
  51. rollbackPacks.push_back(std::move(rollbackVisit));
  52. success = true;
  53. }
  54. void AntilagRollbackGeneratorVisitor::visitTryMoveHero(TryMoveHero & pack)
  55. {
  56. auto rollbackMove = std::make_unique<TryMoveHero>();
  57. auto rollbackFow = std::make_unique<FoWChange>();
  58. const auto * movedHero = gs.getHero(pack.id);
  59. rollbackMove->id = pack.id;
  60. rollbackMove->movePoints = movedHero->movementPointsRemaining();
  61. rollbackMove->result = pack.result;
  62. if (pack.result == TryMoveHero::EMBARK)
  63. rollbackMove->result = TryMoveHero::DISEMBARK;
  64. if (pack.result == TryMoveHero::DISEMBARK)
  65. rollbackMove->result = TryMoveHero::EMBARK;
  66. rollbackMove->start = pack.end;
  67. rollbackMove->end = pack.start;
  68. rollbackFow->mode = ETileVisibility::HIDDEN;
  69. rollbackFow->player = movedHero->getOwner();
  70. rollbackFow->tiles = pack.fowRevealed;
  71. rollbackPacks.push_back(std::move(rollbackMove));
  72. rollbackPacks.push_back(std::move(rollbackFow));
  73. success = true;
  74. }
  75. bool AntilagRollbackGeneratorVisitor::canBeRolledBack() const
  76. {
  77. return success;
  78. }
  79. std::vector<std::unique_ptr<CPackForClient>> AntilagRollbackGeneratorVisitor::getRollbackPacks()
  80. {
  81. return std::move(rollbackPacks);
  82. }
  83. AntilagReplyPredictionVisitor::AntilagReplyPredictionVisitor() = default;
  84. void AntilagReplyPredictionVisitor::visitMoveHero(MoveHero & pack)
  85. {
  86. canBeAppliedValue = true;
  87. }
  88. bool AntilagReplyPredictionVisitor::canBeApplied() const
  89. {
  90. return canBeAppliedValue;
  91. }
  92. AntilagServer::AntilagServer(INetworkHandler & network, const std::shared_ptr<CGameState> & gs)
  93. : gameHandler(std::make_unique<CGameHandler>(*this, gs))
  94. {
  95. antilagNetConnection = network.createAsyncConnection(*this);
  96. antilagGameConnection = std::make_shared<GameConnection>(antilagNetConnection);
  97. }
  98. AntilagServer::~AntilagServer() = default;
  99. void AntilagServer::onDisconnected(const std::shared_ptr<INetworkConnection> & connection, const std::string & errorMessage)
  100. {
  101. // should never be called
  102. throw std::runtime_error("AntilagServer::onDisconnected called!");
  103. }
  104. void AntilagServer::onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<std::byte> & message)
  105. {
  106. std::scoped_lock interfaceLock(ENGINE->interfaceMutex);
  107. auto basePack = antilagGameConnection->retrievePack(message);
  108. auto * serverPack = dynamic_cast<CPackForServer*>(basePack.get());
  109. AntilagReplyPredictionVisitor packVisitor;
  110. serverPack->visit(packVisitor);
  111. if (!packVisitor.canBeApplied())
  112. return;
  113. logGlobal->info("Predicting effects of pack '%s'", typeid(*serverPack).name());
  114. AntilagReplyPrediction newPrediction;
  115. newPrediction.requestID = serverPack->requestID;
  116. newPrediction.senderID = serverPack->player;
  117. predictedReplies.push_back(std::move(newPrediction));
  118. try
  119. {
  120. gameHandler->handleReceivedPack(GameConnectionID::FIRST_CONNECTION, *serverPack);
  121. }
  122. catch (const AntilagRollbackNotSupportedException & )
  123. {
  124. return;
  125. }
  126. }
  127. void AntilagServer::tryPredictReply(const CPackForServer & request)
  128. {
  129. antilagGameConnection->sendPack(request);
  130. logGlobal->info("Scheduled prediction of effects of pack '%s'", typeid(request).name());
  131. }
  132. bool AntilagServer::verifyReply(const CPackForClient & pack)
  133. {
  134. logGlobal->info("Verifying reply: received pack '%s'", typeid(pack).name());
  135. const auto * packageReceived = dynamic_cast<const PackageReceived*>(&pack);
  136. const auto * packageApplied = dynamic_cast<const PackageApplied*>(&pack);
  137. if (packageReceived)
  138. {
  139. assert(currentPackageID == invalidPackageID);
  140. if (!predictedReplies.empty() && predictedReplies.front().requestID == packageReceived->requestID)
  141. {
  142. [[maybe_unused]] const auto & nextPrediction = predictedReplies.front();
  143. assert(nextPrediction.senderID == packageReceived->player);
  144. assert(nextPrediction.requestID == packageReceived->requestID);
  145. currentPackageID = packageReceived->requestID;
  146. }
  147. }
  148. if (currentPackageID == invalidPackageID)
  149. {
  150. // this is system package or reply to actions of another player
  151. // TODO: consider reapplying all our predictions, in case if this event invalidated our prediction
  152. return false;
  153. }
  154. ConnectionPackWriter packWriter;
  155. BinarySerializer serializer(&packWriter);
  156. serializer & &pack;
  157. if (packWriter.buffer == predictedReplies.front().writtenPacks.front().buffer)
  158. {
  159. // Our prediction was sucessful - drop rollback information for this pack
  160. predictedReplies.front().writtenPacks.erase(predictedReplies.front().writtenPacks.begin());
  161. if (predictedReplies.front().writtenPacks.empty())
  162. {
  163. predictedReplies.erase(predictedReplies.begin());
  164. currentPackageID = invalidPackageID;
  165. return true;
  166. }
  167. }
  168. else
  169. {
  170. // Prediction was incorrect - rollback everything that is left in this prediction and use real server packs
  171. for (auto & prediction : boost::adaptors::reverse(predictedReplies.front().writtenPacks))
  172. {
  173. for (auto & pack : prediction.rollbackPacks)
  174. GAME->server().client->handlePack(*pack);
  175. }
  176. predictedReplies.erase(predictedReplies.begin());
  177. currentPackageID = invalidPackageID;
  178. return false;
  179. }
  180. if (packageApplied)
  181. {
  182. assert(currentPackageID == packageApplied->requestID);
  183. assert(!predictedReplies.empty());
  184. assert(currentPackageID == predictedReplies.front().requestID);
  185. assert(predictedReplies.front().writtenPacks.empty());
  186. predictedReplies.erase(predictedReplies.begin());
  187. currentPackageID = invalidPackageID;
  188. }
  189. return true;
  190. }
  191. void AntilagServer::setState(EServerState value)
  192. {
  193. // no-op
  194. }
  195. EServerState AntilagServer::getState() const
  196. {
  197. return EServerState::GAMEPLAY;
  198. }
  199. bool AntilagServer::isPlayerHost(const PlayerColor & color) const
  200. {
  201. return false; // TODO?
  202. }
  203. bool AntilagServer::hasPlayerAt(PlayerColor player, GameConnectionID c) const
  204. {
  205. return true; // TODO?
  206. }
  207. bool AntilagServer::hasBothPlayersAtSameConnection(PlayerColor left, PlayerColor right) const
  208. {
  209. return false; // TODO?
  210. }
  211. void AntilagServer::applyPack(CPackForClient & pack)
  212. {
  213. AntilagRollbackGeneratorVisitor visitor(gameHandler->gameState());
  214. pack.visit(visitor);
  215. if (!visitor.canBeRolledBack())
  216. {
  217. logGlobal->info("Prediction not possible: pack '%s'", typeid(pack).name());
  218. throw AntilagRollbackNotSupportedException(std::string("Prediction not possible ") + typeid(pack).name());
  219. }
  220. logGlobal->info("Prediction: pack '%s'", typeid(pack).name());
  221. ConnectionPackWriter packWriter;
  222. BinarySerializer serializer(&packWriter);
  223. serializer & &pack;
  224. packWriter.rollbackPacks = visitor.getRollbackPacks();
  225. predictedReplies.back().writtenPacks.push_back(std::move(packWriter));
  226. GAME->server().client->handlePack(pack);
  227. }
  228. void AntilagServer::sendPack(CPackForClient & pack, GameConnectionID connectionID)
  229. {
  230. applyPack(pack);
  231. }