mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Issues fixed
This commit is contained in:
		| @@ -624,12 +624,13 @@ void CCreatureSet::armyChanged() | ||||
|  | ||||
| } | ||||
|  | ||||
| void CCreatureSet::serializeJson(JsonSerializeFormat & handler, const std::string & fieldName, const std::optional<int> fixedSize) | ||||
| void CCreatureSet::serializeJson(JsonSerializeFormat & handler, const std::string & armyFieldName, const std::optional<int> fixedSize) | ||||
| { | ||||
| 	if(handler.saving && stacks.empty()) | ||||
| 		return; | ||||
|  | ||||
| 	auto a = handler.enterArray(fieldName); | ||||
| 	handler.serializeEnum("formation", formation, NArmyFormation::names); | ||||
| 	auto a = handler.enterArray(armyFieldName); | ||||
|  | ||||
|  | ||||
| 	if(handler.saving) | ||||
|   | ||||
| @@ -206,6 +206,11 @@ enum class EArmyFormation : uint8_t | ||||
| 	TIGHT | ||||
| }; | ||||
|  | ||||
| namespace NArmyFormation | ||||
| { | ||||
| 	static const std::vector<std::string> names{ "wide", "tight" }; | ||||
| } | ||||
|  | ||||
| class DLL_LINKAGE CCreatureSet : public IArmyDescriptor //seven combined creatures | ||||
| { | ||||
| 	CCreatureSet(const CCreatureSet &) = delete; | ||||
| @@ -284,7 +289,7 @@ public: | ||||
| 		h & formation; | ||||
| 	} | ||||
|  | ||||
| 	void serializeJson(JsonSerializeFormat & handler, const std::string & fieldName, const std::optional<int> fixedSize = std::nullopt); | ||||
| 	void serializeJson(JsonSerializeFormat & handler, const std::string & armyFieldName, const std::optional<int> fixedSize = std::nullopt); | ||||
|  | ||||
| 	operator bool() const | ||||
| 	{ | ||||
|   | ||||
| @@ -160,4 +160,10 @@ const IBonusBearer* CArmedInstance::getBonusBearer() const | ||||
| 	return this; | ||||
| } | ||||
|  | ||||
| void CArmedInstance::serializeJsonOptions(JsonSerializeFormat & handler) | ||||
| { | ||||
| 	CGObjectInstance::serializeJsonOptions(handler); | ||||
| 	CCreatureSet::serializeJson(handler, "army", 7); | ||||
| } | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
|   | ||||
| @@ -18,6 +18,7 @@ VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| class BattleInfo; | ||||
| class CGameState; | ||||
| class JsonSerializeFormat; | ||||
|  | ||||
| class DLL_LINKAGE CArmedInstance: public CGObjectInstance, public CBonusSystemNode, public CCreatureSet, public IConstBonusProvider | ||||
| { | ||||
| @@ -48,6 +49,8 @@ public: | ||||
| 	{ | ||||
| 		return this->tempOwner; | ||||
| 	} | ||||
| 	 | ||||
| 	void serializeJsonOptions(JsonSerializeFormat & handler) override; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
|   | ||||
| @@ -1709,10 +1709,7 @@ void CGHeroInstance::serializeJsonOptions(JsonSerializeFormat & handler) | ||||
| 			setHeroTypeName(typeName); | ||||
| 	} | ||||
|  | ||||
| 	static const std::vector<std::string> FORMATIONS  =	{ "wide", "tight" }; | ||||
|  | ||||
| 	CCreatureSet::serializeJson(handler, "army", 7); | ||||
| 	handler.serializeEnum("formation", formation, FORMATIONS); | ||||
| 	CArmedInstance::serializeJsonOptions(handler); | ||||
|  | ||||
| 	{ | ||||
| 		static constexpr int NO_PATROLING = -1; | ||||
|   | ||||
| @@ -28,9 +28,15 @@ VCMI_LIB_NAMESPACE_BEGIN | ||||
| void CGPandoraBox::init() | ||||
| { | ||||
| 	blockVisit = true; | ||||
| 	configuration.info.emplace_back(); | ||||
| 	configuration.info.back().visitType = Rewardable::EEventType::EVENT_FIRST_VISIT; | ||||
| 	 | ||||
| 	for(auto & i : configuration.info) | ||||
| 	{ | ||||
| 		i.reward.removeObject = true; | ||||
| 		if(!message.empty() && i.message.empty()) | ||||
| 			i.message = MetaString::createFromRawString(message); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGPandoraBox::initObj(CRandomGenerator & rand) | ||||
| @@ -202,14 +208,17 @@ void CGPandoraBox::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answe | ||||
| void CGPandoraBox::serializeJsonOptions(JsonSerializeFormat & handler) | ||||
| { | ||||
| 	CRewardableObject::serializeJsonOptions(handler); | ||||
| 	 | ||||
| 	handler.serializeString("guardMessage", message); | ||||
| 	 | ||||
| 	if(!handler.saving) | ||||
| 	{ | ||||
| 		//backward compatibility | ||||
| 		CCreatureSet::serializeJson(handler, "guards", 7); | ||||
| 		configuration.info.emplace_back(); | ||||
| 		Rewardable::VisitInfo & vinfo = configuration.info.back(); | ||||
| 		//backward compatibility for VCMI maps that use old Pandora Box format | ||||
| 		if(!handler.getCurrent()["guards"].Vector().empty()) | ||||
| 			CCreatureSet::serializeJson(handler, "guards", 7); | ||||
| 		 | ||||
| 		bool hasSomething = false; | ||||
| 		Rewardable::VisitInfo vinfo; | ||||
| 		vinfo.visitType = Rewardable::EEventType::EVENT_FIRST_VISIT; | ||||
| 				 | ||||
| 		handler.serializeInt("experience", vinfo.reward.heroExperience, 0); | ||||
| @@ -230,6 +239,8 @@ void CGPandoraBox::serializeJsonOptions(JsonSerializeFormat & handler) | ||||
| 			for(int idx = 0; idx < vinfo.reward.primary.size(); idx ++) | ||||
| 			{ | ||||
| 				handler.serializeInt(NPrimarySkill::names[idx], vinfo.reward.primary[idx], 0); | ||||
| 				if(vinfo.reward.primary[idx]) | ||||
| 					hasSomething = true; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| @@ -261,6 +272,19 @@ void CGPandoraBox::serializeJsonOptions(JsonSerializeFormat & handler) | ||||
| 				vinfo.reward.secondary[rawId] = level; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		hasSomething = hasSomething | ||||
| 		|| vinfo.reward.heroExperience | ||||
| 		|| vinfo.reward.manaDiff | ||||
| 		|| vinfo.reward.resources.nonZero() | ||||
| 		|| !vinfo.reward.bonuses.empty() | ||||
| 		|| !vinfo.reward.artifacts.empty() | ||||
| 		|| !vinfo.reward.secondary.empty() | ||||
| 		|| !vinfo.reward.artifacts.empty() | ||||
| 		|| !vinfo.reward.creatures.empty(); | ||||
| 		 | ||||
| 		if(hasSomething) | ||||
| 			configuration.info.push_back(vinfo); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1093,11 +1093,10 @@ void CGTownInstance::reset() | ||||
|  | ||||
| void CGTownInstance::serializeJsonOptions(JsonSerializeFormat & handler) | ||||
| { | ||||
| 	static const std::vector<std::string> FORMATIONS  =	{ "wide", "tight" }; | ||||
|  | ||||
| 	CGObjectInstance::serializeJsonOwner(handler); | ||||
| 	CCreatureSet::serializeJson(handler, "army", 7); | ||||
| 	handler.serializeEnum("tightFormation", formation, FORMATIONS); | ||||
| 	if(!handler.saving) | ||||
| 		handler.serializeEnum("tightFormation", formation, NArmyFormation::names); //for old format | ||||
| 	CArmedInstance::serializeJsonOptions(handler); | ||||
| 	handler.serializeString("name", name); | ||||
|  | ||||
| 	{ | ||||
|   | ||||
| @@ -799,7 +799,7 @@ void CGSeerHut::serializeJsonOptions(JsonSerializeFormat & handler) | ||||
| 	 | ||||
| 	if(!handler.saving) | ||||
| 	{ | ||||
| 		//backward compatibility | ||||
| 		//backward compatibility for VCMI maps that use old SeerHut format | ||||
| 		auto s = handler.enterStruct("reward"); | ||||
| 		const JsonNode & rewardsJson = handler.getCurrent(); | ||||
| 		 | ||||
|   | ||||
| @@ -138,7 +138,7 @@ protected: | ||||
| 	void afterAddToMapCommon(CMap * map) const; | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CGSeerHut : public CRewardableObject, public IQuestObject //army is used when giving reward | ||||
| class DLL_LINKAGE CGSeerHut : public CRewardableObject, public IQuestObject | ||||
| { | ||||
| public: | ||||
| 	std::string seerName; | ||||
|   | ||||
| @@ -196,7 +196,7 @@ void CGMine::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) con | ||||
|  | ||||
| void CGMine::serializeJsonOptions(JsonSerializeFormat & handler) | ||||
| { | ||||
| 	CCreatureSet::serializeJson(handler, "army", 7); | ||||
| 	CArmedInstance::serializeJsonOptions(handler); | ||||
|  | ||||
| 	if(isAbandoned()) | ||||
| 	{ | ||||
| @@ -316,7 +316,9 @@ void CGResource::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) | ||||
|  | ||||
| void CGResource::serializeJsonOptions(JsonSerializeFormat & handler) | ||||
| { | ||||
| 	CCreatureSet::serializeJson(handler, "guards", 7); | ||||
| 	CArmedInstance::serializeJsonOptions(handler); | ||||
| 	if(!handler.saving && !handler.getCurrent()["guards"].Vector().empty()) | ||||
| 		CCreatureSet::serializeJson(handler, "guards", 7); | ||||
| 	handler.serializeInt("amount", amount, 0); | ||||
| 	handler.serializeString("guardMessage", message); | ||||
| } | ||||
| @@ -827,7 +829,9 @@ void CGArtifact::afterAddToMap(CMap * map) | ||||
| void CGArtifact::serializeJsonOptions(JsonSerializeFormat& handler) | ||||
| { | ||||
| 	handler.serializeString("guardMessage", message); | ||||
| 	CCreatureSet::serializeJson(handler, "guards" ,7); | ||||
| 	CArmedInstance::serializeJsonOptions(handler); | ||||
| 	if(!handler.saving && !handler.getCurrent()["guards"].Vector().empty()) | ||||
| 		CCreatureSet::serializeJson(handler, "guards", 7); | ||||
|  | ||||
| 	if(handler.saving && ID == Obj::SPELL_SCROLL) | ||||
| 	{ | ||||
| @@ -1233,7 +1237,7 @@ void CGGarrison::serializeJsonOptions(JsonSerializeFormat& handler) | ||||
| { | ||||
| 	handler.serializeBool("removableUnits", removableUnits); | ||||
| 	serializeJsonOwner(handler); | ||||
| 	CCreatureSet::serializeJson(handler, "army", 7); | ||||
| 	CArmedInstance::serializeJsonOptions(handler); | ||||
| } | ||||
|  | ||||
| void CGMagi::reset() | ||||
|   | ||||
| @@ -133,56 +133,18 @@ void Rewardable::Limiter::serializeJson(JsonSerializeFormat & handler) | ||||
| 	handler.serializeInt("manaPoints", manaPoints); | ||||
| 	handler.serializeIdArray("artifacts", artifacts); | ||||
| 	handler.enterArray("creatures").serializeStruct(creatures); | ||||
| 	{ | ||||
| 		auto a = handler.enterArray("primary"); | ||||
| 		a.syncSize(primary); | ||||
| 		for(int i = 0; i < primary.size(); ++i) | ||||
| 			a.serializeInt(i, primary[i]); | ||||
| 	} | ||||
| 	 | ||||
| 	handler.enterArray("primary").serializeArray(primary); | ||||
| 	{ | ||||
| 		auto a = handler.enterArray("secondary"); | ||||
| 		std::vector<std::pair<std::string, std::string>> fieldValue; | ||||
| 		if(handler.saving) | ||||
| 		std::vector<std::pair<SecondarySkill, si32>> fieldValue(secondary.begin(), secondary.end()); | ||||
| 		a.serializeStruct<std::pair<SecondarySkill, si32>>(fieldValue, [](JsonSerializeFormat & h, std::pair<SecondarySkill, si32> & e) | ||||
| 		{ | ||||
| 			for(auto & i : secondary) | ||||
| 			{ | ||||
| 				auto key = VLC->skillh->encodeSkill(i.first); | ||||
| 				auto value = NSecondarySkill::levels.at(i.second); | ||||
| 				fieldValue.emplace_back(key, value); | ||||
| 			} | ||||
| 		} | ||||
| 			h.serializeId("skill", e.first, SecondarySkill{}, VLC->skillh->decodeSkill, VLC->skillh->encodeSkill); | ||||
| 			h.serializeId("level", e.second, 0, [](const std::string & i){return vstd::find_pos(NSecondarySkill::levels, i);}, [](si32 i){return NSecondarySkill::levels.at(i);}); | ||||
| 		}); | ||||
| 		a.syncSize(fieldValue); | ||||
| 		for(int i = 0; i < fieldValue.size(); ++i) | ||||
| 		{ | ||||
| 			auto e = a.enterStruct(i); | ||||
| 			e->serializeString("skill", fieldValue[i].first); | ||||
| 			e->serializeString("level", fieldValue[i].second); | ||||
| 		} | ||||
| 		if(!handler.saving) | ||||
| 		{ | ||||
| 			for(auto & i : fieldValue) | ||||
| 			{ | ||||
| 				const int skillId = VLC->skillh->decodeSkill(i.first); | ||||
| 				if(skillId < 0) | ||||
| 				{ | ||||
| 					logGlobal->error("Invalid secondary skill %s", i.first); | ||||
| 					continue; | ||||
| 				} | ||||
| 				 | ||||
| 				const int level = vstd::find_pos(NSecondarySkill::levels, i.second); | ||||
| 				if(level < 0) | ||||
| 				{ | ||||
| 					logGlobal->error("Invalid secondary skill level%s", i.second); | ||||
| 					continue; | ||||
| 				} | ||||
| 				 | ||||
| 				secondary[SecondarySkill(skillId)] = level; | ||||
| 			} | ||||
| 				 | ||||
| 		} | ||||
| 		secondary = std::map<SecondarySkill, si32>(fieldValue.begin(), fieldValue.end()); | ||||
| 	} | ||||
| 	 | ||||
| 	//sublimiters | ||||
| 	auto serializeSublimitersList = [&handler](const std::string & field, LimitersList & container) | ||||
| 	{ | ||||
|   | ||||
| @@ -119,76 +119,28 @@ void Rewardable::Reward::serializeJson(JsonSerializeFormat & handler) | ||||
| 	handler.serializeIdArray("artifacts", artifacts); | ||||
| 	handler.serializeIdArray("spells", spells); | ||||
| 	handler.enterArray("creatures").serializeStruct(creatures); | ||||
| 	{ | ||||
| 		auto a = handler.enterArray("primary"); | ||||
| 		a.syncSize(primary); | ||||
| 		for(int i = 0; i < primary.size(); ++i) | ||||
| 			a.serializeInt(i, primary[i]); | ||||
| 	} | ||||
| 	 | ||||
| 	handler.enterArray("primary").serializeArray(primary); | ||||
| 	{ | ||||
| 		auto a = handler.enterArray("secondary"); | ||||
| 		std::vector<std::pair<std::string, std::string>> fieldValue; | ||||
| 		if(handler.saving) | ||||
| 		std::vector<std::pair<SecondarySkill, si32>> fieldValue(secondary.begin(), secondary.end()); | ||||
| 		a.serializeStruct<std::pair<SecondarySkill, si32>>(fieldValue, [](JsonSerializeFormat & h, std::pair<SecondarySkill, si32> & e) | ||||
| 		{ | ||||
| 			for(auto & i : secondary) | ||||
| 			{ | ||||
| 				auto key = VLC->skillh->encodeSkill(i.first); | ||||
| 				auto value = NSecondarySkill::levels.at(i.second); | ||||
| 				fieldValue.emplace_back(key, value); | ||||
| 			} | ||||
| 		} | ||||
| 			h.serializeId("skill", e.first, SecondarySkill{}, VLC->skillh->decodeSkill, VLC->skillh->encodeSkill); | ||||
| 			h.serializeId("level", e.second, 0, [](const std::string & i){return vstd::find_pos(NSecondarySkill::levels, i);}, [](si32 i){return NSecondarySkill::levels.at(i);}); | ||||
| 		}); | ||||
| 		a.syncSize(fieldValue); | ||||
| 		for(int i = 0; i < fieldValue.size(); ++i) | ||||
| 		{ | ||||
| 			auto e = a.enterStruct(i); | ||||
| 			e->serializeString("skill", fieldValue[i].first); | ||||
| 			e->serializeString("level", fieldValue[i].second); | ||||
| 		} | ||||
| 		if(!handler.saving) | ||||
| 		{ | ||||
| 			for(auto & i : fieldValue) | ||||
| 			{ | ||||
| 				const int skillId = VLC->skillh->decodeSkill(i.first); | ||||
| 				if(skillId < 0) | ||||
| 				{ | ||||
| 					logGlobal->error("Invalid secondary skill %s", i.first); | ||||
| 					continue; | ||||
| 				} | ||||
| 				 | ||||
| 				const int level = vstd::find_pos(NSecondarySkill::levels, i.second); | ||||
| 				if(level < 0) | ||||
| 				{ | ||||
| 					logGlobal->error("Invalid secondary skill level%s", i.second); | ||||
| 					continue; | ||||
| 				} | ||||
| 				 | ||||
| 				secondary[SecondarySkill(skillId)] = level; | ||||
| 			} | ||||
| 				 | ||||
| 		} | ||||
| 		secondary = std::map<SecondarySkill, si32>(fieldValue.begin(), fieldValue.end()); | ||||
| 	} | ||||
| 	 | ||||
| 	{ | ||||
| 		auto a = handler.enterArray("creaturesChange"); | ||||
| 		std::vector<std::pair<CreatureID, CreatureID>> fieldValue; | ||||
| 		if(handler.saving) | ||||
| 		std::vector<std::pair<CreatureID, CreatureID>> fieldValue(creaturesChange.begin(), creaturesChange.end()); | ||||
| 		a.serializeStruct<std::pair<CreatureID, CreatureID>>(fieldValue, [](JsonSerializeFormat & h, std::pair<CreatureID, CreatureID> & e) | ||||
| 		{ | ||||
| 			for(auto & i : creaturesChange) | ||||
| 				fieldValue.push_back(i); | ||||
| 		} | ||||
| 		a.syncSize(fieldValue); | ||||
| 		for(int i = 0; i < fieldValue.size(); ++i) | ||||
| 		{ | ||||
| 			auto e = a.enterStruct(i); | ||||
| 			e->serializeId("creature", fieldValue[i].first, CreatureID{}); | ||||
| 			e->serializeId("amount", fieldValue[i].second, CreatureID{}); | ||||
| 		} | ||||
| 		if(!handler.saving) | ||||
| 		{ | ||||
| 			for(auto & i : fieldValue) | ||||
| 				creaturesChange[i.first] = i.second; | ||||
| 		} | ||||
| 			h.serializeId("creature", e.first, CreatureID{}); | ||||
| 			h.serializeId("amount", e.second, CreatureID{}); | ||||
| 		}); | ||||
| 		creaturesChange = std::map<CreatureID, CreatureID>(fieldValue.begin(), fieldValue.end()); | ||||
| 	} | ||||
| 	 | ||||
| 	{ | ||||
|   | ||||
| @@ -74,18 +74,44 @@ public: | ||||
| 	///String <-> Json string | ||||
| 	void serializeString(const size_t index, std::string & value); | ||||
|  | ||||
| 	///vector of serializable <-> Json vector of structs | ||||
| 	///vector of anything int-convertible <-> Json vector of integers | ||||
| 	template<typename T> | ||||
| 	void serializeArray(std::vector<T> & value) | ||||
| 	{ | ||||
| 		syncSize(value, JsonNode::JsonType::DATA_STRUCT); | ||||
|  | ||||
| 		for(size_t idx = 0; idx < size(); idx++) | ||||
| 			serializeInt(idx, value[idx]); | ||||
| 	} | ||||
| 	 | ||||
| 	///vector of strings <-> Json vector of strings | ||||
| 	void serializeArray(std::vector<std::string> & value) | ||||
| 	{ | ||||
| 		syncSize(value, JsonNode::JsonType::DATA_STRUCT); | ||||
|  | ||||
| 		for(size_t idx = 0; idx < size(); idx++) | ||||
| 			serializeString(idx, value[idx]); | ||||
| 	} | ||||
| 	 | ||||
| 	///vector of anything with custom serializing function <-> Json vector of structs | ||||
| 	template <typename Element> | ||||
| 	void serializeStruct(std::vector<Element> & value) | ||||
| 	void serializeStruct(std::vector<Element> & value, std::function<void(JsonSerializeFormat&, Element&)> serializer) | ||||
| 	{ | ||||
| 		syncSize(value, JsonNode::JsonType::DATA_STRUCT); | ||||
|  | ||||
| 		for(size_t idx = 0; idx < size(); idx++) | ||||
| 		{ | ||||
| 			auto s = enterStruct(idx); | ||||
| 			value[idx].serializeJson(*owner); | ||||
| 			serializer(*owner, value[idx]); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	///vector of serializable <-> Json vector of structs | ||||
| 	template <typename Element> | ||||
| 	void serializeStruct(std::vector<Element> & value) | ||||
| 	{ | ||||
| 		serializeStruct<Element>(value, [](JsonSerializeFormat & h, Element & e){e.serializeJson(h);}); | ||||
| 	} | ||||
|  | ||||
| 	void resize(const size_t newSize); | ||||
| 	void resize(const size_t newSize, JsonNode::JsonType type); | ||||
|   | ||||
| @@ -208,7 +208,10 @@ bool RewardsWidget::commitChanges() | ||||
| 	object.configuration.visitMode = ui->visitMode->currentIndex(); | ||||
| 	object.configuration.selectMode = ui->selectMode->currentIndex(); | ||||
| 	object.configuration.infoWindowType = EInfoWindowMode(ui->windowMode->currentIndex()); | ||||
| 	object.configuration.onSelect = MetaString::createFromRawString(ui->onSelectText->text().toStdString()); | ||||
| 	if(ui->onSelectText->text().isEmpty()) | ||||
| 		object.configuration.onSelect.clear(); | ||||
| 	else | ||||
| 		object.configuration.onSelect = MetaString::createFromRawString(ui->onSelectText->text().toStdString()); | ||||
| 	object.configuration.canRefuse = ui->canRefuse->isChecked(); | ||||
| 	 | ||||
| 	//reset parameters | ||||
| @@ -226,7 +229,10 @@ void RewardsWidget::saveCurrentVisitInfo(int index) | ||||
| { | ||||
| 	auto & vinfo = object.configuration.info.at(index); | ||||
| 	vinfo.visitType = Rewardable::EEventType::EVENT_FIRST_VISIT; | ||||
| 	vinfo.message = MetaString::createFromRawString(ui->rewardMessage->text().toStdString()); | ||||
| 	if(ui->rewardMessage->text().isEmpty()) | ||||
| 		vinfo.message.clear(); | ||||
| 	else | ||||
| 		vinfo.message = MetaString::createFromRawString(ui->rewardMessage->text().toStdString()); | ||||
| 	 | ||||
| 	vinfo.reward.heroLevel = ui->rHeroLevel->value(); | ||||
| 	vinfo.reward.heroExperience = ui->rHeroExperience->value(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user