1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-15 01:24:45 +02:00

Implement async requests for bonus types

This commit is contained in:
Ivan Savenko
2025-06-13 13:29:31 +03:00
parent 54de24c687
commit bc48337445
8 changed files with 58 additions and 58 deletions

View File

@ -30,10 +30,6 @@ VCMI_LIB_NAMESPACE_BEGIN
///CBonusType ///CBonusType
CBonusType::CBonusType():
hidden(true)
{}
std::string CBonusType::getDescriptionTextID() const std::string CBonusType::getDescriptionTextID() const
{ {
return TextIdentifier( "core", "bonus", identifier, "description").get(); return TextIdentifier( "core", "bonus", identifier, "description").get();
@ -51,6 +47,11 @@ CBonusTypeHandler::CBonusTypeHandler()
}; };
#undef BONUS_NAME #undef BONUS_NAME
for (int i = 0; i < bonusNames.size(); ++i)
{
registerObject(ModScope::scopeBuiltin(), "bonus", bonusNames[i], i);
}
#define BONUS_NAME(x) \ #define BONUS_NAME(x) \
do { \ do { \
bonusTypes.push_back(CBonusType()); \ bonusTypes.push_back(CBonusType()); \
@ -125,7 +126,7 @@ void CBonusTypeHandler::loadObject(std::string scope, std::string name, const Js
if (vstd::contains(bonusNames, name)) if (vstd::contains(bonusNames, name))
{ {
//h3 bonus //h3 bonus
BonusType bonus = stringToBonus(name); BonusType bonus = static_cast<BonusType>(vstd::find_pos(bonusNames, name));
CBonusType & bt = bonusTypes[vstd::to_underlying(bonus)]; CBonusType & bt = bonusTypes[vstd::to_underlying(bonus)];
loadItem(data, bt, name); loadItem(data, bt, name);
logBonus->trace("Loaded bonus type %s", name); logBonus->trace("Loaded bonus type %s", name);
@ -133,6 +134,7 @@ void CBonusTypeHandler::loadObject(std::string scope, std::string name, const Js
else else
{ {
// new bonus // new bonus
registerObject(scope, "bonus", name, bonusNames.size());
bonusNames.push_back(name); bonusNames.push_back(name);
bonusTypes.emplace_back(); bonusTypes.emplace_back();
loadItem(data, bonusTypes.back(), name); loadItem(data, bonusTypes.back(), name);
@ -194,15 +196,6 @@ void CBonusTypeHandler::loadItem(const JsonNode & source, CBonusType & dest, con
} }
} }
BonusType CBonusTypeHandler::stringToBonus(const std::string & name) const
{
auto it = boost::range::find(bonusNames, name);
if (it != bonusNames.end())
return static_cast<BonusType>(it - bonusNames.begin());
return BonusType::NONE;
}
const std::string & CBonusTypeHandler::bonusToString(BonusType bonus) const const std::string & CBonusTypeHandler::bonusToString(BonusType bonus) const
{ {
return bonusNames.at(static_cast<int>(bonus)); return bonusNames.at(static_cast<int>(bonus));

View File

@ -22,7 +22,7 @@ class JsonNode;
class DLL_LINKAGE CBonusType class DLL_LINKAGE CBonusType
{ {
public: public:
CBonusType(); CBonusType() = default;
std::string getDescriptionTextID() const; std::string getDescriptionTextID() const;
@ -36,8 +36,8 @@ private:
std::map<int, std::string> valueDescriptions; std::map<int, std::string> valueDescriptions;
std::string identifier; std::string identifier;
bool creatureNature; bool creatureNature = false;
bool hidden; bool hidden = true;
}; };
class DLL_LINKAGE CBonusTypeHandler : public IBonusTypeHandler class DLL_LINKAGE CBonusTypeHandler : public IBonusTypeHandler
@ -54,7 +54,6 @@ public:
void loadObject(std::string scope, std::string name, const JsonNode & data) override; void loadObject(std::string scope, std::string name, const JsonNode & data) override;
void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override; void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
BonusType stringToBonus(const std::string & name) const;
const std::string & bonusToString(BonusType bonus) const; const std::string & bonusToString(BonusType bonus) const;
bool isCreatureNatureBonus(BonusType bonus) const; bool isCreatureNatureBonus(BonusType bonus) const;

View File

@ -901,7 +901,6 @@ void CCreatureHandler::loadJsonAnimation(CCreature * cre, const JsonNode & graph
void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & config) const void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & config) const
{ {
bool hasCreatureNatureBonus = false;
creature->animDefName = AnimationPath::fromJson(config["graphics"]["animation"]); creature->animDefName = AnimationPath::fromJson(config["graphics"]["animation"]);
//FIXME: MOD COMPATIBILITY //FIXME: MOD COMPATIBILITY
@ -915,15 +914,11 @@ void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & c
b->source = BonusSource::CREATURE_ABILITY; b->source = BonusSource::CREATURE_ABILITY;
b->sid = BonusSourceID(creature->getId()); b->sid = BonusSourceID(creature->getId());
b->duration = BonusDuration::PERMANENT; b->duration = BonusDuration::PERMANENT;
hasCreatureNatureBonus |= LIBRARY->bth->isCreatureNatureBonus(b->type);
creature->addNewBonus(b); creature->addNewBonus(b);
} }
} }
} }
if (!hasCreatureNatureBonus)
creature->addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::LIVING, BonusSource::CREATURE_ABILITY, 0, BonusSourceID(creature->getId())));
LIBRARY->identifiers()->requestIdentifier("faction", config["faction"], [=](si32 faction) LIBRARY->identifiers()->requestIdentifier("faction", config["faction"], [=](si32 faction)
{ {
creature->faction = FactionID(faction); creature->faction = FactionID(faction);
@ -1352,7 +1347,18 @@ CCreatureHandler::~CCreatureHandler()
void CCreatureHandler::afterLoadFinalization() void CCreatureHandler::afterLoadFinalization()
{ {
for(auto & creature : objects)
{
if (!creature)
continue;
auto natureBonuses = creature->getBonuses([](const Bonus * b){
return LIBRARY->bth->isCreatureNatureBonus(b->type);
});
if (natureBonuses->empty())
creature->addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::LIVING, BonusSource::CREATURE_ABILITY, 0, BonusSourceID(creature->getId())));
}
} }
std::set<CreatureID> CCreatureHandler::getDefaultAllowed() const std::set<CreatureID> CCreatureHandler::getDefaultAllowed() const

View File

@ -193,7 +193,7 @@ static void loadBonusSubtype(BonusSubtypeID & subtype, BonusType type, const Jso
} }
} }
static void loadBonusAddInfo(CAddInfo & var, BonusType type, const JsonNode & node) static void loadBonusAddInfo(CAddInfo & var, BonusType type, const JsonNode & value)
{ {
const auto & getFirstValue = [](const JsonNode & jsonNode) -> const JsonNode & const auto & getFirstValue = [](const JsonNode & jsonNode) -> const JsonNode &
{ {
@ -203,7 +203,6 @@ static void loadBonusAddInfo(CAddInfo & var, BonusType type, const JsonNode & no
return jsonNode; return jsonNode;
}; };
const JsonNode & value = node["addInfo"];
if (value.isNull()) if (value.isNull())
return; return;
@ -432,11 +431,16 @@ VCMI_LIB_NAMESPACE_BEGIN
std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonVector & ability_vec) std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonVector & ability_vec)
{ {
auto b = std::make_shared<Bonus>(); auto b = std::make_shared<Bonus>();
std::string type = ability_vec[0].String();
b->type = LIBRARY->bth->stringToBonus(type); const JsonNode & typeNode = ability_vec[0];
const JsonNode & subtypeNode = ability_vec[2];
LIBRARY->identifiers()->requestIdentifier("bonus", typeNode, [b, subtypeNode](si32 bonusID)
{
b->type = BonusType(bonusID);
loadBonusSubtype(b->subtype, b->type, subtypeNode);
});
b->val = static_cast<si32>(ability_vec[1].Float()); b->val = static_cast<si32>(ability_vec[1].Float());
loadBonusSubtype(b->subtype, b->type, ability_vec[2]);
b->additionalInfo = static_cast<si32>(ability_vec[3].Float()); b->additionalInfo = static_cast<si32>(ability_vec[3].Float());
b->duration = BonusDuration::PERMANENT; //TODO: handle flags (as integer) b->duration = BonusDuration::PERMANENT; //TODO: handle flags (as integer)
b->turnsRemain = 0; b->turnsRemain = 0;
@ -517,8 +521,10 @@ std::shared_ptr<const ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter
if (!parameters[0].isNull()) if (!parameters[0].isNull())
{ {
std::string anotherBonusType = parameters[0].String(); LIBRARY->identifiers()->requestIdentifier("bonus", parameters[0], [bonusLimiter](si32 bonusID)
bonusLimiter->type = LIBRARY->bth->stringToBonus(anotherBonusType); {
bonusLimiter->type = BonusType(bonusID);
});
} }
auto findSource = [&](const JsonNode & parameter) auto findSource = [&](const JsonNode & parameter)
@ -631,10 +637,15 @@ std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonNode &ability, const Text
bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b, const TextIdentifier & descriptionID) bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b, const TextIdentifier & descriptionID)
{ {
const JsonNode * value = nullptr; const JsonNode * value = nullptr;
const JsonNode & subtypeNode = ability["subtype"];
const JsonNode & addinfoNode = ability["addInfo"];
b->type = LIBRARY->bth->stringToBonus(ability["type"].String()); LIBRARY->identifiers()->requestIdentifier("bonus", ability["type"], [b, subtypeNode, addinfoNode](si32 bonusID)
{
loadBonusSubtype(b->subtype, b->type, ability["subtype"]); b->type = BonusType(bonusID);
loadBonusSubtype(b->subtype, b->type, subtypeNode);
loadBonusAddInfo(b->additionalInfo, b->type, addinfoNode);
});
b->val = static_cast<si32>(ability["val"].Float()); b->val = static_cast<si32>(ability["val"].Float());
@ -643,9 +654,6 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b, const TextIdentifi
b->valType = static_cast<BonusValueType>(parseByMapN(bonusValueMap, value, "value type ")); b->valType = static_cast<BonusValueType>(parseByMapN(bonusValueMap, value, "value type "));
b->stacking = ability["stacking"].String(); b->stacking = ability["stacking"].String();
loadBonusAddInfo(b->additionalInfo, b->type, ability);
b->turnsRemain = static_cast<si32>(ability["turns"].Float()); b->turnsRemain = static_cast<si32>(ability["turns"].Float());
if(!ability["description"].isNull()) if(!ability["description"].isNull())
@ -768,7 +776,7 @@ CSelector JsonUtils::parseSelector(const JsonNode & ability)
value = &ability["type"]; value = &ability["type"];
if(value->isString()) if(value->isString())
{ {
ret = ret.And(Selector::type()(LIBRARY->bth->stringToBonus(value->String()))); ret = ret.And(Selector::type()(static_cast<BonusType>(*LIBRARY->identifiers()->getIdentifier("bonus", value->String()))));
} }
value = &ability["subtype"]; value = &ability["subtype"];
if(!value->isNull() && type != BonusType::NONE) if(!value->isNull() && type != BonusType::NONE)

View File

@ -86,21 +86,7 @@ CIdentifierStorage::CIdentifierStorage()
void CIdentifierStorage::checkIdentifier(std::string & ID) void CIdentifierStorage::checkIdentifier(std::string & ID)
{ {
if (boost::algorithm::ends_with(ID, ".")) if (boost::algorithm::ends_with(ID, "."))
logMod->warn("BIG WARNING: identifier %s seems to be broken!", ID); logMod->error("BIG WARNING: identifier %s seems to be broken!", ID);
else
{
size_t pos = 0;
do
{
if (std::tolower(ID[pos]) != ID[pos] ) //Not in camelCase
{
logMod->warn("Warning: identifier %s is not in camelCase!", ID);
ID[pos] = std::tolower(ID[pos]);// Try to fix the ID
}
pos = ID.find('.', pos);
}
while(pos++ != std::string::npos);
}
} }
void CIdentifierStorage::requestIdentifier(ObjectCallback callback) const void CIdentifierStorage::requestIdentifier(ObjectCallback callback) const

View File

@ -844,11 +844,13 @@ std::shared_ptr<CSpell> CSpellHandler::loadFromJson(const std::string & scope, c
{ {
for(auto bonusData: json[name].Struct()) for(auto bonusData: json[name].Struct())
{ {
const std::string bonusId = bonusData.first; if(!bonusData.second.Bool())
const bool flag = bonusData.second.Bool(); continue;
if(flag) LIBRARY->identifiers()->requestIdentifier(bonusData.second.getModScope(), "bonus", bonusData.first, [&vec](si32 bonusID)
vec.push_back(LIBRARY->bth->stringToBonus(bonusId)); {
vec.push_back(BonusType(bonusID));
});
} }
}; };

View File

@ -355,7 +355,11 @@ public:
{ {
if(type == "bonus") if(type == "bonus")
{ {
return std::make_shared<SelectorCondition>(Selector::type()(LIBRARY->bth->stringToBonus(identifier))); std::optional bonusID(LIBRARY->identifiers()->getIdentifier(scope, "bonus", identifier, true));
if (bonusID)
return std::make_shared<SelectorCondition>(Selector::type()(BonusType(*bonusID)));
else
logMod->error("Invalid bonus %s type in spell target condition.", identifier);
} }
else if(type == "creature") else if(type == "creature")
{ {

View File

@ -18,6 +18,8 @@
#include "../lib/constants/StringConstants.h" #include "../lib/constants/StringConstants.h"
#include "../lib/entities/artifact/CArtifact.h" #include "../lib/entities/artifact/CArtifact.h"
#include "../lib/mapping/CMap.h" #include "../lib/mapping/CMap.h"
#include "../lib/modding/IdentifierStorage.h"
#include "../lib/modding/ModScope.h"
#include "../lib/rewardable/Configuration.h" #include "../lib/rewardable/Configuration.h"
#include "../lib/rewardable/Limiter.h" #include "../lib/rewardable/Limiter.h"
#include "../lib/rewardable/Reward.h" #include "../lib/rewardable/Reward.h"
@ -341,7 +343,7 @@ void RewardsWidget::saveCurrentVisitInfo(int index)
for(int i = 0; i < ui->bonuses->rowCount(); ++i) for(int i = 0; i < ui->bonuses->rowCount(); ++i)
{ {
auto dur = bonusDurationMap.at(ui->bonuses->item(i, 0)->text().toStdString()); auto dur = bonusDurationMap.at(ui->bonuses->item(i, 0)->text().toStdString());
auto typ = LIBRARY->bth->stringToBonus(ui->bonuses->item(i, 1)->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(); 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.emplace_back(dur, typ, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(object.id));
} }