1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

Fix hero pool persistency between saves

This commit is contained in:
Ivan Savenko
2023-07-11 20:29:44 +03:00
parent 539c508870
commit ec7e046617
5 changed files with 40 additions and 18 deletions

View File

@@ -64,6 +64,7 @@ public:
{ {
h & heroesPool; h & heroesPool;
h & pavailable; h & pavailable;
h & currentTavern;
} }
}; };

View File

@@ -7242,3 +7242,10 @@ void CGameHandler::createObject(const int3 & visitablePosition, Obj type, int32_
no.targetPos = visitablePosition; no.targetPos = visitablePosition;
sendAndApply(&no); sendAndApply(&no);
} }
void CGameHandler::deserializationFix()
{
//FIXME: pointer to GameHandler itself can't be deserialized at the moment since GameHandler is top-level entity in serialization
// restore any places that requires such pointer manually
heroPool->gameHandler = this;
}

View File

@@ -99,6 +99,8 @@ class CGameHandler : public IGameCallback, public CBattleInfoCallback, public En
std::shared_ptr<CApplier<CBaseForGHApply>> applier; std::shared_ptr<CApplier<CBaseForGHApply>> applier;
std::unique_ptr<boost::thread> battleThread; std::unique_ptr<boost::thread> battleThread;
void deserializationFix();
public: public:
std::unique_ptr<HeroPoolProcessor> heroPool; std::unique_ptr<HeroPoolProcessor> heroPool;
@@ -290,6 +292,9 @@ public:
h & heroPool; h & heroPool;
h & getRandomGenerator(); h & getRandomGenerator();
if (!h.saving)
deserializationFix();
#if SCRIPTING_ENABLED #if SCRIPTING_ENABLED
JsonNode scriptsState; JsonNode scriptsState;
if(h.saving) if(h.saving)

View File

@@ -175,38 +175,43 @@ bool HeroPoolProcessor::hireHero(const CGObjectInstance *obj, const HeroTypeID &
return true; return true;
} }
std::set<const CHeroClass *> HeroPoolProcessor::findAvailableClassesFor(const PlayerColor & player) const std::vector<const CHeroClass *> HeroPoolProcessor::findAvailableClassesFor(const PlayerColor & player) const
{ {
std::set<const CHeroClass *> result; std::vector<const CHeroClass *> result;
const auto & hpool = gameHandler->gameState()->hpool; const auto & hpool = gameHandler->gameState()->hpool;
FactionID factionID = gameHandler->getPlayerSettings(player)->castle; FactionID factionID = gameHandler->getPlayerSettings(player)->castle;
for(auto & elem : hpool->unusedHeroesFromPool()) for(auto & elem : hpool->unusedHeroesFromPool())
{ {
if (vstd::contains(result, elem.second->type->heroClass))
continue;
bool heroAvailable = hpool->isHeroAvailableFor(elem.first, player); bool heroAvailable = hpool->isHeroAvailableFor(elem.first, player);
bool heroClassBanned = elem.second->type->heroClass->selectionProbability[factionID] == 0; bool heroClassBanned = elem.second->type->heroClass->selectionProbability[factionID] == 0;
if(heroAvailable && !heroClassBanned) if(heroAvailable && !heroClassBanned)
result.insert(elem.second->type->heroClass); result.push_back(elem.second->type->heroClass);
} }
return result; return result;
} }
std::set<CGHeroInstance *> HeroPoolProcessor::findAvailableHeroesFor(const PlayerColor & player, const CHeroClass * heroClass) const std::vector<CGHeroInstance *> HeroPoolProcessor::findAvailableHeroesFor(const PlayerColor & player, const CHeroClass * heroClass) const
{ {
std::set<CGHeroInstance *> result; std::vector<CGHeroInstance *> result;
const auto & hpool = gameHandler->gameState()->hpool; const auto & hpool = gameHandler->gameState()->hpool;
for(auto & elem : hpool->unusedHeroesFromPool()) for(auto & elem : hpool->unusedHeroesFromPool())
{ {
assert(!vstd::contains(result, elem.second));
bool heroAvailable = hpool->isHeroAvailableFor(elem.first, player); bool heroAvailable = hpool->isHeroAvailableFor(elem.first, player);
bool heroClassMatches = elem.second->type->heroClass == heroClass; bool heroClassMatches = elem.second->type->heroClass == heroClass;
if(heroAvailable && heroClassMatches) if(heroAvailable && heroClassMatches)
result.insert(elem.second); result.push_back(elem.second);
} }
return result; return result;
@@ -224,8 +229,8 @@ const CHeroClass * HeroPoolProcessor::pickClassFor(bool isNative, const PlayerCo
const auto & hpool = gameHandler->gameState()->hpool; const auto & hpool = gameHandler->gameState()->hpool;
const auto & currentTavern = hpool->getHeroesFor(player); const auto & currentTavern = hpool->getHeroesFor(player);
std::set<const CHeroClass *> potentialClasses = findAvailableClassesFor(player); std::vector<const CHeroClass *> potentialClasses = findAvailableClassesFor(player);
std::set<const CHeroClass *> possibleClasses; std::vector<const CHeroClass *> possibleClasses;
if(potentialClasses.empty()) if(potentialClasses.empty())
{ {
@@ -245,7 +250,7 @@ const CHeroClass * HeroPoolProcessor::pickClassFor(bool isNative, const PlayerCo
if (hasSameClass) if (hasSameClass)
continue; continue;
possibleClasses.insert(heroClass); possibleClasses.push_back(heroClass);
} }
if (possibleClasses.empty()) if (possibleClasses.empty())
@@ -259,6 +264,7 @@ const CHeroClass * HeroPoolProcessor::pickClassFor(bool isNative, const PlayerCo
totalWeight += heroClass->selectionProbability.at(factionID); totalWeight += heroClass->selectionProbability.at(factionID);
int roll = getRandomGenerator(player).nextInt(totalWeight - 1); int roll = getRandomGenerator(player).nextInt(totalWeight - 1);
for(const auto & heroClass : possibleClasses) for(const auto & heroClass : possibleClasses)
{ {
roll -= heroClass->selectionProbability.at(factionID); roll -= heroClass->selectionProbability.at(factionID);
@@ -276,7 +282,7 @@ CGHeroInstance * HeroPoolProcessor::pickHeroFor(bool isNative, const PlayerColor
if(!heroClass) if(!heroClass)
return nullptr; return nullptr;
std::set<CGHeroInstance *> possibleHeroes = findAvailableHeroesFor(player, heroClass); std::vector<CGHeroInstance *> possibleHeroes = findAvailableHeroesFor(player, heroClass);
assert(!possibleHeroes.empty()); assert(!possibleHeroes.empty());
if(possibleHeroes.empty()) if(possibleHeroes.empty())
@@ -288,7 +294,10 @@ CGHeroInstance * HeroPoolProcessor::pickHeroFor(bool isNative, const PlayerColor
CRandomGenerator & HeroPoolProcessor::getRandomGenerator(const PlayerColor & player) CRandomGenerator & HeroPoolProcessor::getRandomGenerator(const PlayerColor & player)
{ {
if (playerSeed.count(player) == 0) if (playerSeed.count(player) == 0)
playerSeed.emplace(player, CRandomGenerator(gameHandler->getRandomGenerator().nextInt())); {
int seed = gameHandler->getRandomGenerator().nextInt();
playerSeed.emplace(player, std::make_unique<CRandomGenerator>(seed));
}
return playerSeed.at(player); return *playerSeed.at(player);
} }

View File

@@ -26,23 +26,24 @@ class CGameHandler;
class HeroPoolProcessor : boost::noncopyable class HeroPoolProcessor : boost::noncopyable
{ {
CGameHandler * gameHandler;
/// per-player random generators /// per-player random generators
std::map<PlayerColor, CRandomGenerator> playerSeed; std::map<PlayerColor, std::unique_ptr<CRandomGenerator>> playerSeed;
void clearHeroFromSlot(const PlayerColor & color, TavernHeroSlot slot); void clearHeroFromSlot(const PlayerColor & color, TavernHeroSlot slot);
void selectNewHeroForSlot(const PlayerColor & color, TavernHeroSlot slot, bool needNativeHero, bool giveStartingArmy); void selectNewHeroForSlot(const PlayerColor & color, TavernHeroSlot slot, bool needNativeHero, bool giveStartingArmy);
std::set<const CHeroClass *> findAvailableClassesFor(const PlayerColor & player) const; std::vector<const CHeroClass *> findAvailableClassesFor(const PlayerColor & player) const;
std::set<CGHeroInstance *> findAvailableHeroesFor(const PlayerColor & player, const CHeroClass * heroClass) const; std::vector<CGHeroInstance *> findAvailableHeroesFor(const PlayerColor & player, const CHeroClass * heroClass) const;
const CHeroClass * pickClassFor(bool isNative, const PlayerColor & player); const CHeroClass * pickClassFor(bool isNative, const PlayerColor & player);
CGHeroInstance * pickHeroFor(bool isNative, const PlayerColor & player); CGHeroInstance * pickHeroFor(bool isNative, const PlayerColor & player);
CRandomGenerator & getRandomGenerator(const PlayerColor & player); CRandomGenerator & getRandomGenerator(const PlayerColor & player);
public: public:
CGameHandler * gameHandler;
HeroPoolProcessor(); HeroPoolProcessor();
HeroPoolProcessor(CGameHandler * gameHandler); HeroPoolProcessor(CGameHandler * gameHandler);
@@ -55,7 +56,6 @@ public:
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & gameHandler;
h & playerSeed; h & playerSeed;
} }
}; };