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 & pavailable;
h & currentTavern;
}
};

View File

@@ -7242,3 +7242,10 @@ void CGameHandler::createObject(const int3 & visitablePosition, Obj type, int32_
no.targetPos = visitablePosition;
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::unique_ptr<boost::thread> battleThread;
void deserializationFix();
public:
std::unique_ptr<HeroPoolProcessor> heroPool;
@@ -290,6 +292,9 @@ public:
h & heroPool;
h & getRandomGenerator();
if (!h.saving)
deserializationFix();
#if SCRIPTING_ENABLED
JsonNode scriptsState;
if(h.saving)

View File

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

View File

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