Browse Source

Merge pull request #3502 from IvanSavenko/campaign_localization_fix

Fixed missing translation strings on loading campaign save
Ivan Savenko 1 year ago
parent
commit
bdd649a3be

+ 25 - 0
lib/CGeneralTextHandler.cpp

@@ -264,11 +264,14 @@ void TextLocalizationContainer::registerStringOverride(const std::string & modCo
 
 void TextLocalizationContainer::addSubContainer(const TextLocalizationContainer & container)
 {
+	assert(!vstd::contains(subContainers, &container));
 	subContainers.push_back(&container);
 }
 
 void TextLocalizationContainer::removeSubContainer(const TextLocalizationContainer & container)
 {
+	assert(vstd::contains(subContainers, &container));
+
 	subContainers.erase(std::remove(subContainers.begin(), subContainers.end(), &container), subContainers.end());
 }
 
@@ -414,6 +417,28 @@ void TextLocalizationContainer::jsonSerialize(JsonNode & dest) const
 	}
 }
 
+TextContainerRegistrable::TextContainerRegistrable()
+{
+	VLC->generaltexth->addSubContainer(*this);
+}
+
+TextContainerRegistrable::~TextContainerRegistrable()
+{
+	VLC->generaltexth->removeSubContainer(*this);
+}
+
+TextContainerRegistrable::TextContainerRegistrable(const TextContainerRegistrable & other)
+	: TextLocalizationContainer(other)
+{
+	VLC->generaltexth->addSubContainer(*this);
+}
+
+TextContainerRegistrable::TextContainerRegistrable(TextContainerRegistrable && other) noexcept
+	:TextLocalizationContainer(other)
+{
+	VLC->generaltexth->addSubContainer(*this);
+}
+
 void CGeneralTextHandler::readToVector(const std::string & sourceID, const std::string & sourceName)
 {
 	CLegacyConfigParser parser(TextPath::builtin(sourceName));

+ 12 - 0
lib/CGeneralTextHandler.h

@@ -218,6 +218,18 @@ public:
 	}
 };
 
+class DLL_LINKAGE TextContainerRegistrable : public TextLocalizationContainer
+{
+public:
+	TextContainerRegistrable();
+	~TextContainerRegistrable();
+
+	TextContainerRegistrable(const TextContainerRegistrable & other);
+	TextContainerRegistrable(TextContainerRegistrable && other) noexcept;
+
+	TextContainerRegistrable& operator=(TextContainerRegistrable b) = delete;
+};
+
 /// Handles all text-related data in game
 class DLL_LINKAGE CGeneralTextHandler: public TextLocalizationContainer
 {

+ 7 - 7
lib/campaign/CampaignHandler.cpp

@@ -124,7 +124,7 @@ static std::string convertMapName(std::string input)
 	return input;
 }
 
-std::string CampaignHandler::readLocalizedString(CBinaryReader & reader, std::string filename, std::string modName, std::string encoding, std::string identifier)
+std::string CampaignHandler::readLocalizedString(CampaignHeader & target, CBinaryReader & reader, std::string filename, std::string modName, std::string encoding, std::string identifier)
 {
 	TextIdentifier stringID( "campaign", convertMapName(filename), identifier);
 
@@ -133,7 +133,7 @@ std::string CampaignHandler::readLocalizedString(CBinaryReader & reader, std::st
 	if (input.empty())
 		return "";
 
-	VLC->generaltexth->registerString(modName, stringID, input);
+	target.getTexts().registerString(modName, stringID, input);
 	return stringID.get();
 }
 
@@ -383,8 +383,8 @@ void CampaignHandler::readHeaderFromMemory( CampaignHeader & ret, CBinaryReader
 	ret.version = static_cast<CampaignVersion>(reader.readUInt32());
 	ui8 campId = reader.readUInt8() - 1;//change range of it from [1, 20] to [0, 19]
 	ret.loadLegacyData(campId);
-	ret.name.appendTextID(readLocalizedString(reader, filename, modName, encoding, "name"));
-	ret.description.appendTextID(readLocalizedString(reader, filename, modName, encoding, "description"));
+	ret.name.appendTextID(readLocalizedString(ret, reader, filename, modName, encoding, "name"));
+	ret.description.appendTextID(readLocalizedString(ret, reader, filename, modName, encoding, "description"));
 	if (ret.version > CampaignVersion::RoE)
 		ret.difficultyChoosenByPlayer = reader.readInt8();
 	else
@@ -396,7 +396,7 @@ void CampaignHandler::readHeaderFromMemory( CampaignHeader & ret, CBinaryReader
 	ret.encoding = encoding;
 }
 
-CampaignScenario CampaignHandler::readScenarioFromMemory( CBinaryReader & reader, const CampaignHeader & header)
+CampaignScenario CampaignHandler::readScenarioFromMemory( CBinaryReader & reader, CampaignHeader & header)
 {
 	auto prologEpilogReader = [&](const std::string & identifier) -> CampaignScenarioPrologEpilog
 	{
@@ -410,7 +410,7 @@ CampaignScenario CampaignHandler::readScenarioFromMemory( CBinaryReader & reader
 			ret.prologVideo = CampaignHandler::prologVideoName(index);
 			ret.prologMusic = CampaignHandler::prologMusicName(reader.readUInt8());
 			ret.prologVoice = isOriginalCampaign ? CampaignHandler::prologVoiceName(index) : AudioPath();
-			ret.prologText.appendTextID(readLocalizedString(reader, header.filename, header.modName, header.encoding, identifier));
+			ret.prologText.appendTextID(readLocalizedString(header, reader, header.filename, header.modName, header.encoding, identifier));
 		}
 		return ret;
 	};
@@ -428,7 +428,7 @@ CampaignScenario CampaignHandler::readScenarioFromMemory( CBinaryReader & reader
 	}
 	ret.regionColor = reader.readUInt8();
 	ret.difficulty = reader.readUInt8();
-	ret.regionText.appendTextID(readLocalizedString(reader, header.filename, header.modName, header.encoding, ret.mapName + ".region"));
+	ret.regionText.appendTextID(readLocalizedString(header, reader, header.filename, header.modName, header.encoding, ret.mapName + ".region"));
 	ret.prolog = prologEpilogReader(ret.mapName + ".prolog");
 	ret.epilog = prologEpilogReader(ret.mapName + ".epilog");
 

+ 2 - 2
lib/campaign/CampaignHandler.h

@@ -16,7 +16,7 @@ VCMI_LIB_NAMESPACE_BEGIN
 
 class DLL_LINKAGE CampaignHandler
 {
-	static std::string readLocalizedString(CBinaryReader & reader, std::string filename, std::string modName, std::string encoding, std::string identifier);
+	static std::string readLocalizedString(CampaignHeader & target, CBinaryReader & reader, std::string filename, std::string modName, std::string encoding, std::string identifier);
 
 	static void readCampaign(Campaign * target, const std::vector<ui8> & stream, std::string filename, std::string modName, std::string encoding);
 
@@ -27,7 +27,7 @@ class DLL_LINKAGE CampaignHandler
 
 	//parsers for original H3C campaigns
 	static void readHeaderFromMemory(CampaignHeader & target, CBinaryReader & reader, std::string filename, std::string modName, std::string encoding);
-	static CampaignScenario readScenarioFromMemory(CBinaryReader & reader, const CampaignHeader & header);
+	static CampaignScenario readScenarioFromMemory(CBinaryReader & reader, CampaignHeader & header);
 	static CampaignTravel readScenarioTravelFromMemory(CBinaryReader & reader, CampaignVersion version);
 	/// returns h3c split in parts. 0 = h3c header, 1-end - maps (binary h3m)
 	/// headerOnly - only header will be decompressed, returned vector wont have any maps

+ 5 - 0
lib/campaign/CampaignState.cpp

@@ -169,6 +169,11 @@ const CampaignRegions & CampaignHeader::getRegions() const
 	return campaignRegions;
 }
 
+TextContainerRegistrable & CampaignHeader::getTexts()
+{
+	return textContainer;
+}
+
 bool CampaignState::isConquered(CampaignScenarioID whichScenario) const
 {
 	return vstd::contains(mapsConquered, whichScenario);

+ 9 - 3
lib/campaign/CampaignState.h

@@ -9,9 +9,10 @@
  */
 #pragma once
 
-#include "../lib/GameConstants.h"
-#include "../lib/MetaString.h"
-#include "../lib/filesystem/ResourcePath.h"
+#include "../GameConstants.h"
+#include "../MetaString.h"
+#include "../filesystem/ResourcePath.h"
+#include "../CGeneralTextHandler.h"
 #include "CampaignConstants.h"
 #include "CampaignScenarioPrologEpilog.h"
 
@@ -87,6 +88,8 @@ class DLL_LINKAGE CampaignHeader : public boost::noncopyable
 
 	void loadLegacyData(ui8 campId);
 
+	TextContainerRegistrable textContainer;
+
 public:
 	bool playerSelectedDifficulty() const;
 	bool formatVCMI() const;
@@ -99,6 +102,7 @@ public:
 	AudioPath getMusic() const;
 
 	const CampaignRegions & getRegions() const;
+	TextContainerRegistrable & getTexts();
 
 	template <typename Handler> void serialize(Handler &h, const int formatVersion)
 	{
@@ -112,6 +116,8 @@ public:
 		h & modName;
 		h & music;
 		h & encoding;
+		if (formatVersion >= 832)
+			h & textContainer;
 	}
 };
 

+ 3 - 10
lib/mapping/CMapHeader.cpp

@@ -122,13 +122,9 @@ CMapHeader::CMapHeader() : version(EMapFormat::VCMI), height(72), width(72),
 	setupEvents();
 	allowedHeroes = VLC->heroh->getDefaultAllowed();
 	players.resize(PlayerColor::PLAYER_LIMIT_I);
-	VLC->generaltexth->addSubContainer(*this);
 }
 
-CMapHeader::~CMapHeader()
-{
-	VLC->generaltexth->removeSubContainer(*this);
-}
+CMapHeader::~CMapHeader() = default;
 
 ui8 CMapHeader::levels() const
 {
@@ -137,9 +133,6 @@ ui8 CMapHeader::levels() const
 
 void CMapHeader::registerMapStrings()
 {
-	VLC->generaltexth->removeSubContainer(*this);
-	VLC->generaltexth->addSubContainer(*this);
-	
 	//get supported languages. Assuming that translation containing most strings is the base language
 	std::set<std::string> mapLanguages, mapBaseLanguages;
 	int maxStrings = 0;
@@ -193,7 +186,7 @@ void CMapHeader::registerMapStrings()
 		JsonUtils::mergeCopy(data, translations[language]);
 	
 	for(auto & s : data.Struct())
-		registerString("map", TextIdentifier(s.first), s.second.String(), language);
+		texts.registerString("map", TextIdentifier(s.first), s.second.String(), language);
 }
 
 std::string mapRegisterLocalizedString(const std::string & modContext, CMapHeader & mapHeader, const TextIdentifier & UID, const std::string & localized)
@@ -203,7 +196,7 @@ std::string mapRegisterLocalizedString(const std::string & modContext, CMapHeade
 
 std::string mapRegisterLocalizedString(const std::string & modContext, CMapHeader & mapHeader, const TextIdentifier & UID, const std::string & localized, const std::string & language)
 {
-	mapHeader.registerString(modContext, UID, localized, language);
+	mapHeader.texts.registerString(modContext, UID, localized, language);
 	mapHeader.translations.Struct()[language].Struct()[UID.get()].String() = localized;
 	return UID.get();
 }

+ 3 - 2
lib/mapping/CMapHeader.h

@@ -192,7 +192,7 @@ struct DLL_LINKAGE TriggeredEvent
 };
 
 /// The map header holds information about loss/victory condition,map format, version, players, height, width,...
-class DLL_LINKAGE CMapHeader: public TextLocalizationContainer
+class DLL_LINKAGE CMapHeader
 {
 	void setupEvents();
 public:
@@ -240,13 +240,14 @@ public:
 	
 	/// translations for map to be transferred over network
 	JsonNode translations;
+	TextContainerRegistrable texts;
 	
 	void registerMapStrings();
 
 	template <typename Handler>
 	void serialize(Handler & h, const int Version)
 	{
-		h & static_cast<TextLocalizationContainer&>(*this);
+		h & texts;
 		h & version;
 		h & mods;
 		h & name;