| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- /*
- * AntilagServer.cpp, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
- #include "StdInc.h"
- #include "AntilagServer.h"
- #include "GameEngine.h"
- #include "../server/CGameHandler.h"
- #include "../lib/gameState/CGameState.h"
- #include "../lib/mapObjects/CGHeroInstance.h"
- #include "../lib/serializer/GameConnection.h"
- int ConnectionPackWriter::write(const std::byte * data, unsigned size)
- {
- buffer.insert(buffer.end(), data, data + size);
- return size;
- }
- void AntilagFakeConnection::sendPack(const CPack & pack)
- {
- logGlobal->info("Prediction: pack '%s'", typeid(pack).name());
- ConnectionPackWriter packWriter;
- BinarySerializer serializer(&packWriter);
- serializer & &pack;
- writtenPacks.push_back(std::move(packWriter));
- }
- std::unique_ptr<CPack> AntilagFakeConnection::retrievePack(const std::vector<std::byte> & data)
- {
- throw std::runtime_error("AntilagFakeConnection::retrievePack not implemented");
- }
- int AntilagFakeConnection::getConnectionID() const
- {
- return 0;
- }
- void AntilagRollbackGeneratorVisitor::visitTryMoveHero(TryMoveHero & pack)
- {
- auto rollbackMove = std::make_unique<TryMoveHero>();
- auto rollbackFow = std::make_unique<FoWChange>();
- const auto * movedHero = gs.getHero(pack.id);
- rollbackMove->id = pack.id;
- rollbackMove->movePoints = movedHero->movementPointsRemaining();
- rollbackMove->result = pack.result;
- if (pack.result == TryMoveHero::EMBARK)
- rollbackMove->result = TryMoveHero::DISEMBARK;
- if (pack.result == TryMoveHero::DISEMBARK)
- rollbackMove->result = TryMoveHero::EMBARK;
- rollbackMove->start = pack.end;
- rollbackMove->end = pack.start;
- rollbackFow->mode = ETileVisibility::HIDDEN;
- rollbackFow->player = movedHero->getOwner();
- rollbackFow->tiles = pack.fowRevealed;
- rollbackPacks.push_back(std::move(rollbackMove));
- rollbackPacks.push_back(std::move(rollbackFow));
- success = true;
- }
- bool AntilagRollbackGeneratorVisitor::canBeRolledBack() const
- {
- return success;
- }
- std::vector<std::unique_ptr<CPackForClient>> AntilagRollbackGeneratorVisitor::getRollbackPacks()
- {
- return std::move(rollbackPacks);
- }
- AntilagReplyPredictionVisitor::AntilagReplyPredictionVisitor() = default;
- void AntilagReplyPredictionVisitor::visitMoveHero(MoveHero & pack)
- {
- canBeAppliedValue = true;
- }
- bool AntilagReplyPredictionVisitor::canBeApplied() const
- {
- return canBeAppliedValue;
- }
- AntilagServer::AntilagServer(INetworkHandler & network, const std::shared_ptr<CGameState> & gs)
- : gameHandler(std::make_unique<CGameHandler>(*this, gs))
- {
- antilagNetConnection = network.createAsyncConnection(*this);
- antilagGameConnection = std::make_shared<GameConnection>(antilagNetConnection);
- }
- AntilagServer::~AntilagServer() = default;
- void AntilagServer::onDisconnected(const std::shared_ptr<INetworkConnection> & connection, const std::string & errorMessage)
- {
- // should never be called
- throw std::runtime_error("AntilagServer::onDisconnected called!");
- }
- void AntilagServer::onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<std::byte> & message)
- {
- std::scoped_lock interfaceLock(ENGINE->interfaceMutex);
- auto basePack = antilagGameConnection->retrievePack(message);
- auto * serverPack = dynamic_cast<CPackForServer*>(basePack.get());
- AntilagReplyPredictionVisitor packVisitor;
- serverPack->visit(packVisitor);
- if (!packVisitor.canBeApplied())
- return;
- logGlobal->info("Predicting effects of pack '%s'", typeid(*serverPack).name());
- auto newConnection = std::make_shared<AntilagFakeConnection>();
- newConnection->requestID = serverPack->requestID;
- newConnection->senderID = serverPack->player;
- predictedReplies.push_back(std::move(newConnection));
- gameHandler->handleReceivedPack(predictedReplies.back(), *serverPack);
- }
- void AntilagServer::tryPredictReply(const CPackForServer & request)
- {
- antilagGameConnection->sendPack(request);
- logGlobal->info("Scheduled prediction of effects of pack '%s'", typeid(request).name());
- }
- bool AntilagServer::verifyReply(const CPackForClient & pack)
- {
- logGlobal->info("Verifying reply: received pack '%s'", typeid(pack).name());
- const auto * packageReceived = dynamic_cast<const PackageReceived*>(&pack);
- const auto * packageApplied = dynamic_cast<const PackageApplied*>(&pack);
- if (packageReceived)
- {
- assert(currentPackageID == invalidPackageID);
- assert(!predictedReplies.empty());
- const auto & nextPrediction = predictedReplies.front();
- assert(nextPrediction->senderID == packageReceived->player);
- assert(nextPrediction->requestID == packageReceived->requestID);
- currentPackageID = packageReceived->requestID;
- }
- if (currentPackageID == invalidPackageID)
- {
- // this is system package or reply to actions of another player
- // TODO: consider reapplying all our predictions, in case if this event invalidated our prediction
- return false;
- }
- ConnectionPackWriter packWriter;
- BinarySerializer serializer(&packWriter);
- serializer & &pack;
- if (packWriter.buffer == predictedReplies.front()->writtenPacks.front().buffer)
- predictedReplies.front()->writtenPacks.erase(predictedReplies.front()->writtenPacks.begin());
- else
- throw std::runtime_error("TODO: IMPLEMENT PACK ROLLBACK");
- if (packageApplied)
- {
- assert(currentPackageID == packageApplied->requestID);
- assert(!predictedReplies.empty());
- assert(currentPackageID == predictedReplies.front()->requestID);
- assert(predictedReplies.front()->writtenPacks.empty());
- predictedReplies.erase(predictedReplies.begin());
- currentPackageID = invalidPackageID;
- }
- return true;
- }
- void AntilagServer::setState(EServerState value)
- {
- // no-op
- }
- EServerState AntilagServer::getState() const
- {
- return EServerState::GAMEPLAY;
- }
- bool AntilagServer::isPlayerHost(const PlayerColor & color) const
- {
- return false; // TODO?
- }
- bool AntilagServer::hasPlayerAt(PlayerColor player, const std::shared_ptr<IGameConnection> & c) const
- {
- return true; // TODO?
- }
- bool AntilagServer::hasBothPlayersAtSameConnection(PlayerColor left, PlayerColor right) const
- {
- return false; // TODO?
- }
- void AntilagServer::broadcastPack(CPackForClient & pack)
- {
- AntilagReplyPredictionVisitor visitor;
- pack.visit(visitor);
- predictedReplies.back()->sendPack(pack);
- }
|