1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-21 00:19:29 +02:00

Use bonus only as shared_ptr to avoid memory corruption

This commit is contained in:
Ivan Savenko
2025-06-16 16:22:21 +03:00
parent 4044e03c0a
commit 463c404a83
19 changed files with 62 additions and 67 deletions

View File

@ -142,15 +142,10 @@ std::shared_ptr<CArtifact> CArtHandler::loadFromJson(const std::string & scope,
if(!node["growing"].isNull())
{
for(auto bonus : node["growing"]["bonusesPerLevel"].Vector())
{
art->bonusesPerLevel.emplace_back(static_cast<ui16>(bonus["level"].Float()), Bonus());
JsonUtils::parseBonus(bonus["bonus"], &art->bonusesPerLevel.back().second);
}
art->bonusesPerLevel.emplace_back(static_cast<ui16>(bonus["level"].Float()), JsonUtils::parseBonus(bonus["bonus"]));
for(auto bonus : node["growing"]["thresholdBonuses"].Vector())
{
art->thresholdBonuses.emplace_back(static_cast<ui16>(bonus["level"].Float()), Bonus());
JsonUtils::parseBonus(bonus["bonus"], &art->thresholdBonuses.back().second);
}
art->thresholdBonuses.emplace_back(static_cast<ui16>(bonus["level"].Float()), JsonUtils::parseBonus(bonus["bonus"]));
}
art->id = ArtifactID(index);

View File

@ -59,22 +59,22 @@ bool CGrowingArtifact::isGrowing() const
return !bonusesPerLevel.empty() || !thresholdBonuses.empty();
}
std::vector <std::pair<ui16, Bonus>> & CGrowingArtifact::getBonusesPerLevel()
std::vector <std::pair<ui16, std::shared_ptr<Bonus>>> & CGrowingArtifact::getBonusesPerLevel()
{
return bonusesPerLevel;
}
const std::vector <std::pair<ui16, Bonus>> & CGrowingArtifact::getBonusesPerLevel() const
const std::vector <std::pair<ui16, std::shared_ptr<Bonus>>> & CGrowingArtifact::getBonusesPerLevel() const
{
return bonusesPerLevel;
}
std::vector <std::pair<ui16, Bonus>> & CGrowingArtifact::getThresholdBonuses()
std::vector <std::pair<ui16, std::shared_ptr<Bonus>>> & CGrowingArtifact::getThresholdBonuses()
{
return thresholdBonuses;
}
const std::vector <std::pair<ui16, Bonus>> & CGrowingArtifact::getThresholdBonuses() const
const std::vector <std::pair<ui16, std::shared_ptr<Bonus>>> & CGrowingArtifact::getThresholdBonuses() const
{
return thresholdBonuses;
}

View File

@ -54,15 +54,15 @@ class DLL_LINKAGE CGrowingArtifact
protected:
CGrowingArtifact() = default;
std::vector<std::pair<ui16, Bonus>> bonusesPerLevel; // Bonus given each n levels
std::vector<std::pair<ui16, Bonus>> thresholdBonuses; // After certain level they will be added once
std::vector<std::pair<ui16, std::shared_ptr<Bonus>>> bonusesPerLevel; // Bonus given each n levels
std::vector<std::pair<ui16, std::shared_ptr<Bonus>>> thresholdBonuses; // After certain level they will be added once
public:
bool isGrowing() const;
std::vector<std::pair<ui16, Bonus>> & getBonusesPerLevel();
const std::vector<std::pair<ui16, Bonus>> & getBonusesPerLevel() const;
std::vector<std::pair<ui16, Bonus>> & getThresholdBonuses();
const std::vector<std::pair<ui16, Bonus>> & getThresholdBonuses() const;
std::vector<std::pair<ui16, std::shared_ptr<Bonus>>> & getBonusesPerLevel();
const std::vector<std::pair<ui16, std::shared_ptr<Bonus>>> & getBonusesPerLevel() const;
std::vector<std::pair<ui16, std::shared_ptr<Bonus>>> & getThresholdBonuses();
const std::vector<std::pair<ui16, std::shared_ptr<Bonus>>> & getThresholdBonuses() const;
};
class DLL_LINKAGE CChargedArtifact

View File

@ -109,7 +109,7 @@ void CGrowingArtifactInstance::growingUp()
// Every n levels
if(artInst->valOfBonuses(BonusType::ARTIFACT_GROWING) % bonus.first == 0)
{
artInst->accumulateBonus(std::make_shared<Bonus>(bonus.second));
artInst->accumulateBonus(std::make_shared<Bonus>(*bonus.second));
}
}
for(const auto & bonus : artType->getThresholdBonuses())
@ -117,7 +117,7 @@ void CGrowingArtifactInstance::growingUp()
// At n level
if(artInst->valOfBonuses(BonusType::ARTIFACT_GROWING) == bonus.first)
{
artInst->addNewBonus(std::make_shared<Bonus>(bonus.second));
artInst->addNewBonus(std::make_shared<Bonus>(*bonus.second));
}
}

View File

@ -580,13 +580,13 @@ JsonRandom::JsonRandom(IGameInfoCallback * cb, IGameRandomizer & gameRandomizer)
return ret;
}
std::vector<Bonus> JsonRandom::loadBonuses(const JsonNode & value)
std::vector<std::shared_ptr<Bonus>> JsonRandom::loadBonuses(const JsonNode & value)
{
std::vector<Bonus> ret;
std::vector<std::shared_ptr<Bonus>> ret;
for (const JsonNode & entry : value.Vector())
{
if(auto bonus = JsonUtils::parseBonus(entry))
ret.push_back(*bonus);
ret.push_back(bonus);
}
return ret;
}

View File

@ -91,7 +91,7 @@ public:
std::vector<HeroTypeID> loadHeroes(const JsonNode & value);
std::vector<HeroClassID> loadHeroClasses(const JsonNode & value);
static std::vector<Bonus> loadBonuses(const JsonNode & value);
static std::vector<std::shared_ptr<Bonus>> loadBonuses(const JsonNode & value);
};
VCMI_LIB_NAMESPACE_END

View File

@ -46,12 +46,12 @@ std::shared_ptr<CGObjectInstance> CRewardableConstructor::create(IGameInfoCallba
return ret;
}
void CRewardableConstructor::assignBonuses(std::vector<Bonus> & bonuses, MapObjectID objectID) const
void CRewardableConstructor::assignBonuses(std::vector<std::shared_ptr<Bonus>> & bonuses, MapObjectID objectID) const
{
for (auto & bonus : bonuses)
{
bonus.source = BonusSource::OBJECT_TYPE;
bonus.sid = BonusSourceID(objectID);
bonus->source = BonusSource::OBJECT_TYPE;
bonus->sid = BonusSourceID(objectID);
}
}

View File

@ -20,7 +20,7 @@ class DLL_LINKAGE CRewardableConstructor : public AObjectTypeHandler
{
Rewardable::Info objectInfo;
void assignBonuses(std::vector<Bonus> & bonuses, MapObjectID objectID) const;
void assignBonuses(std::vector<std::shared_ptr<Bonus>> & bonuses, MapObjectID objectID) const;
void initTypeData(const JsonNode & config) override;
bool blockVisit = false;

View File

@ -269,7 +269,7 @@ void BoatInstanceConstructor::initializeObject(CGBoat * boat) const
boat->onboardAssaultAllowed = onboardAssaultAllowed;
boat->onboardVisitAllowed = onboardVisitAllowed;
for(auto & b : bonuses)
boat->addNewBonus(std::make_shared<Bonus>(b));
boat->addNewBonus(b);
}
AnimationPath BoatInstanceConstructor::getBoatAnimationName() const

View File

@ -110,7 +110,7 @@ class DLL_LINKAGE BoatInstanceConstructor : public CDefaultObjectTypeHandler<CGB
protected:
void initTypeData(const JsonNode & config) override;
std::vector<Bonus> bonuses;
std::vector<std::shared_ptr<Bonus>> bonuses;
EPathfindingLayer layer;
bool onboardAssaultAllowed; //if true, hero can attack units from transport
bool onboardVisitAllowed; //if true, hero can visit objects from transport

View File

@ -109,10 +109,10 @@ void CGPandoraBox::grantRewardWithMessage(IGameEventCallback & gameEvents, const
for(auto b : vi.reward.heroBonuses)
{
if(b.val && b.type == BonusType::MORALE)
txt = setText(b.val > 0, 179, 178, h);
if(b.val && b.type == BonusType::LUCK)
txt = setText(b.val > 0, 181, 180, h);
if(b->val && b->type == BonusType::MORALE)
txt = setText(b->val > 0, 179, 178, h);
if(b->val && b->type == BonusType::LUCK)
txt = setText(b->val > 0, 181, 180, h);
}
sendInfoWindow(txt, temp);
@ -229,11 +229,11 @@ void CGPandoraBox::serializeJsonOptions(JsonSerializeFormat & handler)
int val = 0;
handler.serializeInt("morale", val, 0);
if(val)
vinfo.reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id));
vinfo.reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id)));
handler.serializeInt("luck", val, 0);
if(val)
vinfo.reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id));
vinfo.reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id)));
vinfo.reward.resources.serializeJson(handler, "resources");
{

View File

@ -703,9 +703,9 @@ void CGSeerHut::serializeJsonOptions(JsonSerializeFormat & handler)
if(metaTypeName == "mana")
reward.manaDiff = val;
if(metaTypeName == "morale")
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id));
reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id)));
if(metaTypeName == "luck")
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id));
reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id)));
if(metaTypeName == "resource")
{
auto rawId = *LIBRARY->identifiers()->getIdentifier(ModScope::scopeMap(), fullIdentifier, false);

View File

@ -73,7 +73,7 @@ TownRewardableBuildingInstance::TownRewardableBuildingInstance(CGTownInstance *
configuration = generateConfiguration(gameRandomizer);
}
void TownRewardableBuildingInstance::assignBonuses(std::vector<Bonus> & bonuses) const
void TownRewardableBuildingInstance::assignBonuses(std::vector<std::shared_ptr<Bonus>> & bonuses) const
{
const auto & building = town->getTown()->buildings.at(getBuildingType());
@ -81,13 +81,13 @@ void TownRewardableBuildingInstance::assignBonuses(std::vector<Bonus> & bonuses)
{
if (building->mapObjectLikeBonuses.hasValue())
{
bonus.source = BonusSource::OBJECT_TYPE;
bonus.sid = BonusSourceID(building->mapObjectLikeBonuses);
bonus->source = BonusSource::OBJECT_TYPE;
bonus->sid = BonusSourceID(building->mapObjectLikeBonuses);
}
else
{
bonus.source = BonusSource::TOWN_STRUCTURE;
bonus.sid = BonusSourceID(building->getUniqueTypeID());
bonus->source = BonusSource::TOWN_STRUCTURE;
bonus->sid = BonusSourceID(building->getUniqueTypeID());
}
}
}

View File

@ -58,7 +58,7 @@ class DLL_LINKAGE TownRewardableBuildingInstance : public TownBuildingInstance,
bool wasVisitedBefore(const CGHeroInstance * contextHero) const override;
void grantReward(IGameEventCallback & gameEvents, ui32 rewardID, const CGHeroInstance * hero) const override;
Rewardable::Configuration generateConfiguration(IGameRandomizer & gameRandomizer) const;
void assignBonuses(std::vector<Bonus> & bonuses) const;
void assignBonuses(std::vector<std::shared_ptr<Bonus>> & bonuses) const;
const IObjectInterface * getObject() const override;
bool wasVisited(PlayerColor player) const override;

View File

@ -1083,9 +1083,9 @@ void CMapLoaderH3M::readBoxContent(CGPandoraBox * object, const int3 & mapPositi
reward.heroExperience = reader->readUInt32();
reward.manaDiff = reader->readInt32();
if(auto val = reader->readInt8Checked(-3, 3))
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(idToBeGiven));
reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(idToBeGiven)));
if(auto val = reader->readInt8Checked(-3, 3))
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(idToBeGiven));
reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(idToBeGiven)));
reader->readResources(reward.resources);
for(int x = 0; x < GameConstants::PRIMARY_SKILLS; ++x)
@ -2275,12 +2275,12 @@ void CMapLoaderH3M::readSeerHutQuest(CGSeerHut * hut, const int3 & position, con
}
case ESeerHutRewardType::MORALE:
{
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, reader->readInt8Checked(-3, 3), BonusSourceID(idToBeGiven));
reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, reader->readInt8Checked(-3, 3), BonusSourceID(idToBeGiven)));
break;
}
case ESeerHutRewardType::LUCK:
{
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, reader->readInt8Checked(-3, 3), BonusSourceID(idToBeGiven));
reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, reader->readInt8Checked(-3, 3), BonusSourceID(idToBeGiven)));
break;
}
case ESeerHutRewardType::RESOURCES:

View File

@ -152,24 +152,24 @@ void Rewardable::Interface::grantRewardAfterLevelup(IGameEventCallback & gameEve
gameEvents.setMovePoints(&smp);
}
for(const Bonus & bonus : info.reward.heroBonuses)
for(const auto & bonus : info.reward.heroBonuses)
{
GiveBonus gb(GiveBonus::ETarget::OBJECT, hero->id, bonus);
GiveBonus gb(GiveBonus::ETarget::OBJECT, hero->id, *bonus);
gameEvents.giveHeroBonus(&gb);
}
if (hero->getCommander())
{
for(const Bonus & bonus : info.reward.commanderBonuses)
for(const auto & bonus : info.reward.commanderBonuses)
{
GiveBonus gb(GiveBonus::ETarget::HERO_COMMANDER, hero->id, bonus);
GiveBonus gb(GiveBonus::ETarget::HERO_COMMANDER, hero->id, *bonus);
gameEvents.giveHeroBonus(&gb);
}
}
for(const Bonus & bonus : info.reward.playerBonuses)
for(const auto & bonus : info.reward.playerBonuses)
{
GiveBonus gb(GiveBonus::ETarget::PLAYER, hero->getOwner(), bonus);
GiveBonus gb(GiveBonus::ETarget::PLAYER, hero->getOwner(), *bonus);
gameEvents.giveHeroBonus(&gb);
}

View File

@ -81,10 +81,10 @@ void Rewardable::Reward::loadComponents(std::vector<Component> & comps, const CG
for (auto & bonus : heroBonuses)
{
if (bonus.type == BonusType::MORALE)
comps.emplace_back(ComponentType::MORALE, bonus.val);
if (bonus.type == BonusType::LUCK)
comps.emplace_back(ComponentType::LUCK, bonus.val);
if (bonus->type == BonusType::MORALE)
comps.emplace_back(ComponentType::MORALE, bonus->val);
if (bonus->type == BonusType::LUCK)
comps.emplace_back(ComponentType::LUCK, bonus->val);
}
if (heroExperience)

View File

@ -86,9 +86,9 @@ struct DLL_LINKAGE Reward final
std::vector<CStackBasicDescriptor> guards;
/// list of bonuses, e.g. morale/luck
std::vector<Bonus> heroBonuses;
std::vector<Bonus> commanderBonuses;
std::vector<Bonus> playerBonuses;
std::vector<std::shared_ptr<Bonus>> heroBonuses;
std::vector<std::shared_ptr<Bonus>> commanderBonuses;
std::vector<std::shared_ptr<Bonus>> playerBonuses;
/// skills that hero may receive or lose
std::vector<si32> primary;

View File

@ -345,7 +345,7 @@ void RewardsWidget::saveCurrentVisitInfo(int index)
auto dur = bonusDurationMap.at(ui->bonuses->item(i, 0)->text().toStdString());
auto typ = static_cast<BonusType>(*LIBRARY->identifiers()->getIdentifier(ModScope::scopeBuiltin(), "bonus", ui->bonuses->item(i, 1)->text().toStdString()));
auto val = ui->bonuses->item(i, 2)->data(Qt::UserRole).toInt();
vinfo.reward.heroBonuses.emplace_back(dur, typ, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(object.id));
vinfo.reward.heroBonuses.push_back(std::make_shared<Bonus>(dur, typ, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(object.id)));
}
vinfo.limiter.dayOfWeek = ui->lDayOfWeek->currentIndex();
@ -483,7 +483,7 @@ void RewardsWidget::loadCurrentVisitInfo(int index)
for(auto & i : vinfo.reward.heroBonuses)
{
auto dur = vstd::findKey(bonusDurationMap, i.duration);
auto dur = vstd::findKey(bonusDurationMap, i->duration);
for(int i = 0; i < ui->bonusDuration->count(); ++i)
{
if(ui->bonusDuration->itemText(i) == QString::fromStdString(dur))
@ -493,7 +493,7 @@ void RewardsWidget::loadCurrentVisitInfo(int index)
}
}
std::string typ = LIBRARY->bth->bonusToString(i.type);
std::string typ = LIBRARY->bth->bonusToString(i->type);
for(int i = 0; i < ui->bonusType->count(); ++i)
{
if(ui->bonusType->itemText(i) == QString::fromStdString(typ))
@ -503,7 +503,7 @@ void RewardsWidget::loadCurrentVisitInfo(int index)
}
}
ui->bonusValue->setValue(i.val);
ui->bonusValue->setValue(i->val);
on_bonusAdd_clicked();
}
@ -819,8 +819,8 @@ void RewardsDelegate::updateModelData(QAbstractItemModel * model, const QModelIn
QStringList bonusesList;
for (auto & bonus : vinfo.reward.heroBonuses)
{
std::string bonusName = LIBRARY->bth->bonusToString(bonus.type);
bonusesList += QString("%1 %2 (%3)").arg(QString::fromStdString(vstd::findKey(bonusDurationMap, bonus.duration))).arg(QString::fromStdString(bonusName)).arg(bonus.val);
std::string bonusName = LIBRARY->bth->bonusToString(bonus->type);
bonusesList += QString("%1 %2 (%3)").arg(QString::fromStdString(vstd::findKey(bonusDurationMap, bonus->duration))).arg(QString::fromStdString(bonusName)).arg(bonus->val);
}
textList += QObject::tr("Bonuses: %1").arg(bonusesList.join(", "));
}