Browse Source

Implement async requests for bonus types

Ivan Savenko 4 months ago
parent
commit
bc48337445

+ 7 - 14
lib/CBonusTypeHandler.cpp

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

+ 3 - 4
lib/CBonusTypeHandler.h

@@ -22,7 +22,7 @@ class JsonNode;
 class DLL_LINKAGE CBonusType
 {
 public:
-	CBonusType();
+	CBonusType() = default;
 
 	std::string getDescriptionTextID() const;
 
@@ -36,8 +36,8 @@ private:
 	std::map<int, std::string> valueDescriptions;
 	std::string identifier;
 
-	bool creatureNature;
-	bool hidden;
+	bool creatureNature = false;
+	bool hidden = true;
 };
 
 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, size_t index) override;
 
-	BonusType stringToBonus(const std::string & name) const;
 	const std::string & bonusToString(BonusType bonus) const;
 
 	bool isCreatureNatureBonus(BonusType bonus) const;

+ 11 - 5
lib/CCreatureHandler.cpp

@@ -901,7 +901,6 @@ void CCreatureHandler::loadJsonAnimation(CCreature * cre, const JsonNode & graph
 
 void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & config) const
 {
-	bool hasCreatureNatureBonus = false;
 	creature->animDefName = AnimationPath::fromJson(config["graphics"]["animation"]);
 
 	//FIXME: MOD COMPATIBILITY
@@ -915,15 +914,11 @@ void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & c
 				b->source = BonusSource::CREATURE_ABILITY;
 				b->sid = BonusSourceID(creature->getId());
 				b->duration = BonusDuration::PERMANENT;
-				hasCreatureNatureBonus |= LIBRARY->bth->isCreatureNatureBonus(b->type);
 				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)
 	{
 		creature->faction = FactionID(faction);
@@ -1352,7 +1347,18 @@ CCreatureHandler::~CCreatureHandler()
 
 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

+ 22 - 14
lib/json/JsonBonus.cpp

@@ -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 &
 	{
@@ -203,7 +203,6 @@ static void loadBonusAddInfo(CAddInfo & var, BonusType type, const JsonNode & no
 			return jsonNode;
 	};
 
-	const JsonNode & value = node["addInfo"];
 	if (value.isNull())
 		return;
 
@@ -432,11 +431,16 @@ VCMI_LIB_NAMESPACE_BEGIN
 std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonVector & ability_vec)
 {
 	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());
-	loadBonusSubtype(b->subtype, b->type, ability_vec[2]);
 	b->additionalInfo = static_cast<si32>(ability_vec[3].Float());
 	b->duration = BonusDuration::PERMANENT; //TODO: handle flags (as integer)
 	b->turnsRemain = 0;
@@ -517,8 +521,10 @@ std::shared_ptr<const ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter
 
 				if (!parameters[0].isNull())
 				{
-					std::string anotherBonusType = parameters[0].String();
-					bonusLimiter->type = LIBRARY->bth->stringToBonus(anotherBonusType);
+					LIBRARY->identifiers()->requestIdentifier("bonus", parameters[0], [bonusLimiter](si32 bonusID)
+					{
+						bonusLimiter->type = BonusType(bonusID);
+					});
 				}
 
 				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)
 {
 	const JsonNode * value = nullptr;
+	const JsonNode & subtypeNode = ability["subtype"];
+	const JsonNode & addinfoNode = ability["addInfo"];
 
-	b->type = LIBRARY->bth->stringToBonus(ability["type"].String());
-
-	loadBonusSubtype(b->subtype, b->type, ability["subtype"]);
+	LIBRARY->identifiers()->requestIdentifier("bonus", ability["type"], [b, subtypeNode, addinfoNode](si32 bonusID)
+	{
+		b->type = BonusType(bonusID);
+		loadBonusSubtype(b->subtype, b->type, subtypeNode);
+		loadBonusAddInfo(b->additionalInfo, b->type, addinfoNode);
+	});
 
 	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->stacking = ability["stacking"].String();
-
-	loadBonusAddInfo(b->additionalInfo, b->type, ability);
-
 	b->turnsRemain = static_cast<si32>(ability["turns"].Float());
 
 	if(!ability["description"].isNull())
@@ -768,7 +776,7 @@ CSelector JsonUtils::parseSelector(const JsonNode & ability)
 	value = &ability["type"];
 	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"];
 	if(!value->isNull() && type != BonusType::NONE)

+ 1 - 15
lib/modding/IdentifierStorage.cpp

@@ -86,21 +86,7 @@ CIdentifierStorage::CIdentifierStorage()
 void CIdentifierStorage::checkIdentifier(std::string & ID)
 {
 	if (boost::algorithm::ends_with(ID, "."))
-		logMod->warn("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);
-	}
+		logMod->error("BIG WARNING: identifier %s seems to be broken!", ID);
 }
 
 void CIdentifierStorage::requestIdentifier(ObjectCallback callback) const

+ 6 - 4
lib/spells/CSpellHandler.cpp

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

+ 5 - 1
lib/spells/TargetCondition.cpp

@@ -355,7 +355,11 @@ public:
 	{
 		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")
 		{

+ 3 - 1
mapeditor/inspector/rewardswidget.cpp

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