فهرست منبع

Separate map text identifiers from global

nordsoft 2 سال پیش
والد
کامیت
9098126684
5فایلهای تغییر یافته به همراه141 افزوده شده و 69 حذف شده
  1. 67 48
      lib/CGeneralTextHandler.cpp
  2. 63 18
      lib/CGeneralTextHandler.h
  3. 6 0
      lib/mapping/CMapHeader.cpp
  4. 4 2
      lib/mapping/CMapHeader.h
  5. 1 1
      lib/mapping/MapFormatH3M.cpp

+ 67 - 48
lib/CGeneralTextHandler.cpp

@@ -247,22 +247,38 @@ bool CLegacyConfigParser::endLine()
 	return curr < end;
 }
 
-void CGeneralTextHandler::readToVector(const std::string & sourceID, const std::string & sourceName)
+void TextLocalizationContainer::registerStringOverride(const std::string & modContext, const std::string & language, const TextIdentifier & UID, const std::string & localized)
 {
-	CLegacyConfigParser parser(TextPath::builtin(sourceName));
-	size_t index = 0;
-	do
-	{
-		registerString( "core", {sourceID, index}, parser.readString());
-		index += 1;
-	}
-	while (parser.endLine());
+	assert(!modContext.empty());
+	assert(!language.empty());
+
+	// NOTE: implicitly creates entry, intended - strings added by maps, campaigns, vcmi and potentially - UI mods are not registered anywhere at the moment
+	auto & entry = stringsLocalizations[UID.get()];
+
+	entry.overrideLanguage = language;
+	entry.overrideValue = localized;
+	if (entry.modContext.empty())
+		entry.modContext = modContext;
 }
 
-const std::string & CGeneralTextHandler::deserialize(const TextIdentifier & identifier) const
+void TextLocalizationContainer::addSubContainer(const TextLocalizationContainer & container)
+{
+	subContainers.insert(&container);
+}
+
+void TextLocalizationContainer::removeSubContainer(const TextLocalizationContainer & container)
+{
+	subContainers.erase(&container);
+}
+
+const std::string & TextLocalizationContainer::deserialize(const TextIdentifier & identifier) const
 {
 	if(stringsLocalizations.count(identifier.get()) == 0)
 	{
+		for(const auto * container : subContainers)
+			if(container->identifierExists(identifier))
+				return container->deserialize(identifier);
+		
 		logGlobal->error("Unable to find localization for string '%s'", identifier.get());
 		return identifier.get();
 	}
@@ -274,7 +290,7 @@ const std::string & CGeneralTextHandler::deserialize(const TextIdentifier & iden
 	return entry.baseValue;
 }
 
-void CGeneralTextHandler::registerString(const std::string & modContext, const TextIdentifier & UID, const std::string & localized)
+void TextLocalizationContainer::registerString(const std::string & modContext, const TextIdentifier & UID, const std::string & localized)
 {
 	assert(!modContext.empty());
 	assert(!getModLanguage(modContext).empty());
@@ -307,21 +323,7 @@ void CGeneralTextHandler::registerString(const std::string & modContext, const T
 	}
 }
 
-void CGeneralTextHandler::registerStringOverride(const std::string & modContext, const std::string & language, const TextIdentifier & UID, const std::string & localized)
-{
-	assert(!modContext.empty());
-	assert(!language.empty());
-
-	// NOTE: implicitly creates entry, intended - strings added by maps, campaigns, vcmi and potentially - UI mods are not registered anywhere at the moment
-	auto & entry = stringsLocalizations[UID.get()];
-
-	entry.overrideLanguage = language;
-	entry.overrideValue = localized;
-	if (entry.modContext.empty())
-		entry.modContext = modContext;
-}
-
-bool CGeneralTextHandler::validateTranslation(const std::string & language, const std::string & modContext, const JsonNode & config) const
+bool TextLocalizationContainer::validateTranslation(const std::string & language, const std::string & modContext, const JsonNode & config) const
 {
 	bool allPresent = true;
 
@@ -372,12 +374,50 @@ bool CGeneralTextHandler::validateTranslation(const std::string & language, cons
 	return allPresent && allFound;
 }
 
-void CGeneralTextHandler::loadTranslationOverrides(const std::string & language, const std::string & modContext, const JsonNode & config)
+void TextLocalizationContainer::loadTranslationOverrides(const std::string & language, const std::string & modContext, const JsonNode & config)
 {
 	for(const auto & node : config.Struct())
 		registerStringOverride(modContext, language, node.first, node.second.String());
 }
 
+bool TextLocalizationContainer::identifierExists(const TextIdentifier & UID) const
+{
+	return stringsLocalizations.count(UID.get());
+}
+
+void TextLocalizationContainer::dumpAllTexts()
+{
+	logGlobal->info("BEGIN TEXT EXPORT");
+	for(const auto & entry : stringsLocalizations)
+	{
+		if (!entry.second.overrideValue.empty())
+			logGlobal->info(R"("%s" : "%s",)", entry.first, TextOperations::escapeString(entry.second.overrideValue));
+		else
+			logGlobal->info(R"("%s" : "%s",)", entry.first, TextOperations::escapeString(entry.second.baseValue));
+	}
+
+	logGlobal->info("END TEXT EXPORT");
+}
+
+std::string TextLocalizationContainer::getModLanguage(const std::string & modContext)
+{
+	if (modContext == "core")
+		return CGeneralTextHandler::getInstalledLanguage();
+	return VLC->modh->getModLanguage(modContext);
+}
+
+void CGeneralTextHandler::readToVector(const std::string & sourceID, const std::string & sourceName)
+{
+	CLegacyConfigParser parser(TextPath::builtin(sourceName));
+	size_t index = 0;
+	do
+	{
+		registerString( "core", {sourceID, index}, parser.readString());
+		index += 1;
+	}
+	while (parser.endLine());
+}
+
 CGeneralTextHandler::CGeneralTextHandler():
 	victoryConditions(*this, "core.vcdesc"   ),
 	lossCondtions    (*this, "core.lcdesc"   ),
@@ -591,20 +631,6 @@ int32_t CGeneralTextHandler::pluralText(const int32_t textIndex, const int32_t c
 	return textIndex + 1;
 }
 
-void CGeneralTextHandler::dumpAllTexts()
-{
-	logGlobal->info("BEGIN TEXT EXPORT");
-	for(const auto & entry : stringsLocalizations)
-	{
-		if (!entry.second.overrideValue.empty())
-			logGlobal->info(R"("%s" : "%s",)", entry.first, TextOperations::escapeString(entry.second.overrideValue));
-		else
-			logGlobal->info(R"("%s" : "%s",)", entry.first, TextOperations::escapeString(entry.second.baseValue));
-	}
-
-	logGlobal->info("END TEXT EXPORT");
-}
-
 size_t CGeneralTextHandler::getCampaignLength(size_t campaignID) const
 {
 	assert(campaignID < scenariosCountPerCampaign.size());
@@ -614,13 +640,6 @@ size_t CGeneralTextHandler::getCampaignLength(size_t campaignID) const
 	return 0;
 }
 
-std::string CGeneralTextHandler::getModLanguage(const std::string & modContext)
-{
-	if (modContext == "core")
-		return getInstalledLanguage();
-	return VLC->modh->getModLanguage(modContext);
-}
-
 std::string CGeneralTextHandler::getPreferredLanguage()
 {
 	assert(!settings["general"]["language"].String().empty());

+ 63 - 18
lib/CGeneralTextHandler.h

@@ -113,9 +113,9 @@ public:
 	{}
 };
 
-/// Handles all text-related data in game
-class DLL_LINKAGE CGeneralTextHandler
+class DLL_LINKAGE TextLocalizationContainer
 {
+protected:
 	struct StringState
 	{
 		/// Human-readable string that was added on registration
@@ -132,21 +132,26 @@ class DLL_LINKAGE CGeneralTextHandler
 
 		/// ID of mod that created this string
 		std::string modContext;
+		
+		template <typename Handler>
+		void serialize(Handler & h, const int Version)
+		{
+			h & baseValue;
+			h & baseLanguage;
+			h & modContext;
+		}
 	};
-
+	
 	/// map identifier -> localization
 	std::unordered_map<std::string, StringState> stringsLocalizations;
-
-	void readToVector(const std::string & sourceID, const std::string & sourceName);
-
-	/// number of scenarios in specific campaign. TODO: move to a better location
-	std::vector<size_t> scenariosCountPerCampaign;
-
-	std::string getModLanguage(const std::string & modContext);
-
+	
+	std::set<const TextLocalizationContainer *> subContainers;
+	
 	/// add selected string to internal storage as high-priority strings
 	void registerStringOverride(const std::string & modContext, const std::string & language, const TextIdentifier & UID, const std::string & localized);
-
+	
+	std::string getModLanguage(const std::string & modContext);
+	
 public:
 	/// validates translation of specified language for specified mod
 	/// returns true if localization is valid and complete
@@ -157,13 +162,12 @@ public:
 	/// Any entries loaded by this will have priority over texts registered normally
 	void loadTranslationOverrides(const std::string & language, const std::string & modContext, JsonNode const & file);
 
+	// returns true if identifier with such name was registered, even if not translated to current language
+	bool identifierExists(const TextIdentifier & UID) const;
+	
 	/// add selected string to internal storage
 	void registerString(const std::string & modContext, const TextIdentifier & UID, const std::string & localized);
-
-	// returns true if identifier with such name was registered, even if not translated to current language
-	// not required right now, can be added if necessary
-	// bool identifierExists( const std::string identifier) const;
-
+	
 	/// returns translated version of a string that can be displayed to user
 	template<typename  ... Args>
 	std::string translate(std::string arg1, Args ... args) const
@@ -174,10 +178,51 @@ public:
 
 	/// converts identifier into user-readable string
 	const std::string & deserialize(const TextIdentifier & identifier) const;
-
+	
 	/// Debug method, dumps all currently known texts into console using Json-like format
 	void dumpAllTexts();
+	
+	/// Add or override subcontainer which can store identifiers
+	void addSubContainer(const TextLocalizationContainer & container);
+	
+	/// Remove subcontainer with give name
+	void removeSubContainer(const TextLocalizationContainer & container);
+	
+	template <typename Handler>
+	void serialize(Handler & h, const int Version)
+	{
+		std::string key;
+		auto sz = stringsLocalizations.size();
+		h & sz;
+		if(h.saving)
+		{
+			for(auto s : stringsLocalizations)
+			{
+				key = s.first;
+				h & key;
+				h & s.second;
+			}
+		}
+		else
+		{
+			for(size_t i = 0; i < sz; ++i)
+			{
+				h & key;
+				h & stringsLocalizations[key];
+			}
+		}
+	}
+};
+
+/// Handles all text-related data in game
+class DLL_LINKAGE CGeneralTextHandler: public TextLocalizationContainer
+{
+	void readToVector(const std::string & sourceID, const std::string & sourceName);
 
+	/// number of scenarios in specific campaign. TODO: move to a better location
+	std::vector<size_t> scenariosCountPerCampaign;
+
+public:
 	LegacyTextContainer allTexts;
 
 	LegacyTextContainer arraytxt;

+ 6 - 0
lib/mapping/CMapHeader.cpp

@@ -127,6 +127,12 @@ 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);
 }
 
 ui8 CMapHeader::levels() const

+ 4 - 2
lib/mapping/CMapHeader.h

@@ -14,6 +14,7 @@
 #include "../LogicalExpression.h"
 #include "../int3.h"
 #include "../MetaString.h"
+#include "../CGeneralTextHandler.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -199,7 +200,7 @@ struct DLL_LINKAGE TriggeredEvent
 };
 
 /// The map header holds information about loss/victory condition,map format, version, players, height, width,...
-class DLL_LINKAGE CMapHeader
+class DLL_LINKAGE CMapHeader: public TextLocalizationContainer
 {
 	void setupEvents();
 public:
@@ -213,7 +214,7 @@ public:
 	static const int MAP_SIZE_GIANT = 252;
 
 	CMapHeader();
-	virtual ~CMapHeader() = default;
+	virtual ~CMapHeader();
 
 	ui8 levels() const;
 
@@ -248,6 +249,7 @@ public:
 	template <typename Handler>
 	void serialize(Handler & h, const int Version)
 	{
+		h & static_cast<TextLocalizationContainer&>(*this);
 		h & version;
 		h & mods;
 		h & name;

+ 1 - 1
lib/mapping/MapFormatH3M.cpp

@@ -2274,7 +2274,7 @@ std::string CMapLoaderH3M::readLocalizedString(const TextIdentifier & stringIden
 	if(mapString.empty())
 		return "";
 
-	VLC->generaltexth->registerString(modName, fullIdentifier, mapString);
+	mapHeader->registerString(modName, fullIdentifier, mapString);
 	return fullIdentifier.get();
 }