Przeglądaj źródła

Failed prediction will now rollback all assumed changes

Ivan Savenko 4 miesięcy temu
rodzic
commit
2bcc2229c6
2 zmienionych plików z 80 dodań i 7 usunięć
  1. 74 6
      client/AntilagServer.cpp
  2. 6 1
      client/AntilagServer.h

+ 74 - 6
client/AntilagServer.cpp

@@ -20,12 +20,49 @@
 #include "../lib/serializer/GameConnection.h"
 #include "GameInstance.h"
 
+class DLL_LINKAGE AntilagRollbackNotSupportedException : public std::runtime_error
+{
+public:
+	using std::runtime_error::runtime_error;
+};
+
+
 int ConnectionPackWriter::write(const std::byte * data, unsigned size)
 {
 	buffer.insert(buffer.end(), data, data + size);
 	return size;
 }
 
+void AntilagRollbackGeneratorVisitor::visitPackageReceived(PackageReceived & pack)
+{
+	success = true;
+	// no-op rollback?
+}
+
+void AntilagRollbackGeneratorVisitor::visitPackageApplied(PackageApplied & pack)
+{
+	success = true;
+	// no-op rollback?
+}
+
+void AntilagRollbackGeneratorVisitor::visitPlayerBlocked(PlayerBlocked & pack)
+{
+	success = true;
+	// no-op rollback?
+}
+
+void AntilagRollbackGeneratorVisitor::visitHeroVisitCastle(HeroVisitCastle & pack)
+{
+	auto rollbackVisit = std::make_unique<HeroVisitCastle>();
+	rollbackVisit->startVisit = !pack.startVisit;
+	rollbackVisit->tid = pack.tid;
+	rollbackVisit->hid = pack.hid;
+
+	rollbackPacks.push_back(std::move(rollbackVisit));
+
+	success = true;
+}
+
 void AntilagRollbackGeneratorVisitor::visitTryMoveHero(TryMoveHero & pack)
 {
 	auto rollbackMove = std::make_unique<TryMoveHero>();
@@ -107,7 +144,14 @@ void AntilagServer::onPacketReceived(const std::shared_ptr<INetworkConnection> &
 	newPrediction.senderID = serverPack->player;
 	predictedReplies.push_back(std::move(newPrediction));
 
-	gameHandler->handleReceivedPack(GameConnectionID::FIRST_CONNECTION, *serverPack);
+	try
+	{
+		gameHandler->handleReceivedPack(GameConnectionID::FIRST_CONNECTION, *serverPack);
+	}
+	catch (const AntilagRollbackNotSupportedException & )
+	{
+		return;
+	}
 }
 
 void AntilagServer::tryPredictReply(const CPackForServer & request)
@@ -148,9 +192,29 @@ bool AntilagServer::verifyReply(const CPackForClient & pack)
 	serializer & &pack;
 
 	if (packWriter.buffer == predictedReplies.front().writtenPacks.front().buffer)
+	{
+		// Our prediction was sucessful - drop rollback information for this pack
 		predictedReplies.front().writtenPacks.erase(predictedReplies.front().writtenPacks.begin());
+
+		if (predictedReplies.front().writtenPacks.empty())
+		{
+			predictedReplies.erase(predictedReplies.begin());
+			currentPackageID = invalidPackageID;
+			return true;
+		}
+	}
 	else
-		throw std::runtime_error("TODO: IMPLEMENT PACK ROLLBACK");
+	{
+		// Prediction was incorrect - rollback everything that is left in this prediction and use real server packs
+		for (auto & prediction : boost::adaptors::reverse(predictedReplies.front().writtenPacks))
+		{
+			for (auto & pack : prediction.rollbackPacks)
+				GAME->server().client->handlePack(*pack);
+		}
+		predictedReplies.erase(predictedReplies.begin());
+		currentPackageID = invalidPackageID;
+		return false;
+	}
 
 	if (packageApplied)
 	{
@@ -192,16 +256,20 @@ bool AntilagServer::hasBothPlayersAtSameConnection(PlayerColor left, PlayerColor
 
 void AntilagServer::applyPack(CPackForClient & pack)
 {
-//	AntilagReplyPredictionVisitor visitor;
-//	pack.visit(visitor);
-//	if (!visitor.canBeApplied())
-//		throw std::runtime_error("TODO: IMPLEMENT INTERRUPTION");
+	AntilagRollbackGeneratorVisitor visitor(gameHandler->gameState());
+	pack.visit(visitor);
+	if (!visitor.canBeRolledBack())
+	{
+		logGlobal->info("Prediction not possible: pack '%s'", typeid(pack).name());
+		throw AntilagRollbackNotSupportedException(std::string("Prediction not possible ") + typeid(pack).name());
+	}
 
 	logGlobal->info("Prediction: pack '%s'", typeid(pack).name());
 
 	ConnectionPackWriter packWriter;
 	BinarySerializer serializer(&packWriter);
 	serializer & &pack;
+	packWriter.rollbackPacks = visitor.getRollbackPacks();
 	predictedReplies.back().writtenPacks.push_back(std::move(packWriter));
 
 	GAME->server().client->handlePack(pack);

+ 6 - 1
client/AntilagServer.h

@@ -26,6 +26,7 @@ class ConnectionPackWriter final : public IBinaryWriter
 {
 public:
 	std::vector<std::byte> buffer;
+	std::vector<std::unique_ptr<CPackForClient>> rollbackPacks;
 
 	int write(const std::byte * data, unsigned size) final;
 };
@@ -91,12 +92,15 @@ private:
 	std::vector<std::unique_ptr<CPackForClient>> rollbackPacks;
 	bool success = false;
 
+	void visitPackageReceived(PackageReceived & pack) override;
+	void visitPackageApplied(PackageApplied & pack) override;
+	void visitPlayerBlocked(PlayerBlocked & pack) override;
 	//void visitSetResources(SetResources & pack) override;
 	//void visitSetPrimarySkill(SetPrimarySkill & pack) override;
 	//void visitSetHeroExperience(SetHeroExperience & pack) override;
 	//void visitGiveStackExperience(GiveStackExperience & pack) override;
 	//void visitSetSecSkill(SetSecSkill & pack) override;
-	//void visitHeroVisitCastle(HeroVisitCastle & pack) override;
+	void visitHeroVisitCastle(HeroVisitCastle & pack) override;
 	//void visitSetMana(SetMana & pack) override;
 	//void visitSetMovePoints(SetMovePoints & pack) override;
 	//void visitSetResearchedSpells(SetResearchedSpells & pack) override;
@@ -183,6 +187,7 @@ class AntilagServer final : public IGameServer, public INetworkConnectionListene
 	std::vector<AntilagReplyPrediction> predictedReplies;
 	std::shared_ptr<INetworkConnection> antilagNetConnection;
 	std::shared_ptr<GameConnection> antilagGameConnection;
+//	std::shared_ptr<CGameState> & gameState;
 	std::unique_ptr<CGameHandler> gameHandler;
 
 	static constexpr uint32_t invalidPackageID = std::numeric_limits<uint32_t>::max();