Failed prediction will now rollback all assumed changes

This commit is contained in:
Ivan Savenko
2025-07-20 23:54:39 +03:00
parent 241da5937d
commit 2bcc2229c6
2 changed files with 80 additions and 7 deletions
+74 -6
View File
@@ -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
View File
@@ -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();