浏览代码

New version for map format

nordsoft 2 年之前
父节点
当前提交
ba1dbbbb1d
共有 5 个文件被更改,包括 101 次插入7 次删除
  1. 21 4
      lib/CGeneralTextHandler.cpp
  2. 4 0
      lib/CGeneralTextHandler.h
  3. 3 0
      lib/mapping/CMapHeader.h
  4. 62 3
      lib/mapping/MapFormatJson.cpp
  5. 11 0
      lib/mapping/MapFormatJson.h

+ 21 - 4
lib/CGeneralTextHandler.cpp

@@ -11,6 +11,7 @@
 #include "CGeneralTextHandler.h"
 
 #include "filesystem/Filesystem.h"
+#include "serializer/JsonSerializeFormat.h"
 #include "CConfigHandler.h"
 #include "GameSettings.h"
 #include "mapObjects/CQuest.h"
@@ -290,10 +291,10 @@ const std::string & TextLocalizationContainer::deserialize(const TextIdentifier
 	return entry.baseValue;
 }
 
-void TextLocalizationContainer::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, const std::string & language)
 {
 	assert(!modContext.empty());
-	assert(!getModLanguage(modContext).empty());
+	assert(!Languages::getLanguageOptions(language).identifier.empty());
 	assert(UID.get().find("..") == std::string::npos); // invalid identifier - there is section that was evaluated to empty string
 	//assert(stringsLocalizations.count(UID.get()) == 0); // registering already registered string?
 
@@ -303,7 +304,7 @@ void TextLocalizationContainer::registerString(const std::string & modContext, c
 
 		if(value.baseLanguage.empty())
 		{
-			value.baseLanguage = getModLanguage(modContext);
+			value.baseLanguage = language;
 			value.baseValue = localized;
 		}
 		else
@@ -315,7 +316,7 @@ void TextLocalizationContainer::registerString(const std::string & modContext, c
 	else
 	{
 		StringState result;
-		result.baseLanguage = getModLanguage(modContext);
+		result.baseLanguage = language;
 		result.baseValue = localized;
 		result.modContext = modContext;
 
@@ -323,6 +324,12 @@ void TextLocalizationContainer::registerString(const std::string & modContext, c
 	}
 }
 
+void TextLocalizationContainer::registerString(const std::string & modContext, const TextIdentifier & UID, const std::string & localized)
+{
+	assert(!getModLanguage(modContext).empty());
+	registerString(modContext, UID, localized, getModLanguage(modContext));
+}
+
 bool TextLocalizationContainer::validateTranslation(const std::string & language, const std::string & modContext, const JsonNode & config) const
 {
 	bool allPresent = true;
@@ -406,6 +413,16 @@ std::string TextLocalizationContainer::getModLanguage(const std::string & modCon
 	return VLC->modh->getModLanguage(modContext);
 }
 
+void TextLocalizationContainer::jsonSerialize(JsonNode & dest) const
+{
+	for(auto & s : stringsLocalizations)
+	{
+		dest.Struct()[s.first].String() = s.second.baseValue;
+		if(!s.second.overrideValue.empty())
+			dest.Struct()[s.first].String() = s.second.overrideValue;
+	}
+}
+
 void CGeneralTextHandler::readToVector(const std::string & sourceID, const std::string & sourceName)
 {
 	CLegacyConfigParser parser(TextPath::builtin(sourceName));

+ 4 - 0
lib/CGeneralTextHandler.h

@@ -15,6 +15,7 @@ VCMI_LIB_NAMESPACE_BEGIN
 
 class CInputStream;
 class JsonNode;
+class JsonSerializeFormat;
 
 /// Parser for any text files from H3
 class DLL_LINKAGE CLegacyConfigParser
@@ -167,6 +168,7 @@ public:
 	
 	/// add selected string to internal storage
 	void registerString(const std::string & modContext, const TextIdentifier & UID, const std::string & localized);
+	void registerString(const std::string & modContext, const TextIdentifier & UID, const std::string & localized, const std::string & language);
 	
 	/// returns translated version of a string that can be displayed to user
 	template<typename  ... Args>
@@ -188,6 +190,8 @@ public:
 	/// Remove subcontainer with give name
 	void removeSubContainer(const TextLocalizationContainer & container);
 	
+	void jsonSerialize(JsonNode & dest) const;
+	
 	template <typename Handler>
 	void serialize(Handler & h, const int Version)
 	{

+ 3 - 0
lib/mapping/CMapHeader.h

@@ -270,6 +270,9 @@ public:
 		h & defeatMessage;
 		h & defeatIconIndex;
 	}
+	
+	/// do not serialize, used only in map editor to write translations properly
+	JsonNode mapEditorTranslations;
 };
 
 VCMI_LIB_NAMESPACE_END

+ 62 - 3
lib/mapping/MapFormatJson.cpp

@@ -35,6 +35,7 @@
 #include "../constants/StringConstants.h"
 #include "../serializer/JsonDeserializer.h"
 #include "../serializer/JsonSerializer.h"
+#include "../Languages.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -341,8 +342,8 @@ namespace TerrainDetail
 }
 
 ///CMapFormatJson
-const int CMapFormatJson::VERSION_MAJOR = 1;
-const int CMapFormatJson::VERSION_MINOR = 3;
+const int CMapFormatJson::VERSION_MAJOR = 2;
+const int CMapFormatJson::VERSION_MINOR = 0;
 
 const std::string CMapFormatJson::HEADER_FILE_NAME = "header.json";
 const std::string CMapFormatJson::OBJECTS_FILE_NAME = "objects.json";
@@ -906,6 +907,11 @@ std::unique_ptr<CMapHeader> CMapLoaderJson::loadMapHeader()
 	return result;
 }
 
+bool CMapLoaderJson::isExistArchive(const std::string & archiveFilename)
+{
+	return loader.existsResource(JsonPath::builtin(archiveFilename));
+}
+
 JsonNode CMapLoaderJson::getFromArchive(const std::string & archiveFilename)
 {
 	JsonPath resource = JsonPath::builtin(archiveFilename);
@@ -938,7 +944,7 @@ void CMapLoaderJson::readHeader(const bool complete)
 
 	fileVersionMajor = static_cast<int>(header["versionMajor"].Integer());
 
-	if(fileVersionMajor != VERSION_MAJOR)
+	if(fileVersionMajor > VERSION_MAJOR)
 	{
 		logGlobal->error("Unsupported map format version: %d", fileVersionMajor);
 		throw std::runtime_error("Unsupported map format version");
@@ -998,6 +1004,8 @@ void CMapLoaderJson::readHeader(const bool complete)
 
 	if(complete)
 		readOptions(handler);
+	
+	readTranslations();
 }
 
 void CMapLoaderJson::readTerrainTile(const std::string & src, TerrainTile & tile)
@@ -1259,6 +1267,36 @@ void CMapLoaderJson::readObjects()
 	});
 }
 
+void CMapLoaderJson::readTranslations()
+{
+	auto language = CGeneralTextHandler::getPreferredLanguage();
+	JsonNode data;
+
+	if(!isExistArchive(language + ".json"))
+	{
+		//english is preferrable
+		language = Languages::getLanguageOptions(Languages::ELanguages::ENGLISH).identifier;
+		std::list<Languages::Options> options{Languages::getLanguageList().begin(), Languages::getLanguageList().end()};
+		while(!isExistArchive(language + ".json") && !options.empty())
+		{
+			language = options.front().identifier;
+			options.pop_front();
+		}
+		
+		if(!isExistArchive(language + ".json"))
+		{
+			logGlobal->info("Map doesn't have any translation");
+			return;
+		}
+	}
+
+	data = getFromArchive(language + ".json");
+	
+	for(auto & s : data.Struct())
+		mapHeader->registerString("map", TextIdentifier(s.first), s.second.String(), language);
+}
+
+
 ///CMapSaverJson
 CMapSaverJson::CMapSaverJson(CInputOutputStream * stream)
 	: buffer(stream)
@@ -1340,6 +1378,12 @@ void CMapSaverJson::writeHeader()
 	writeTeams(handler);
 
 	writeOptions(handler);
+	
+	for(auto & s : mapHeader->mapEditorTranslations.Struct())
+	{
+		mapHeader->loadTranslationOverrides(s.first, "map", s.second);
+		writeTranslations(s.first);
+	}
 
 	addToArchive(header, HEADER_FILE_NAME);
 }
@@ -1440,5 +1484,20 @@ void CMapSaverJson::writeObjects()
 	addToArchive(data, OBJECTS_FILE_NAME);
 }
 
+void CMapSaverJson::writeTranslations(const std::string & language)
+{
+	if(Languages::getLanguageOptions(language).identifier.empty())
+	{
+		logGlobal->error("Serializing of unsupported language %s is not permitted", language);
+		return;
+	}
+		
+	logGlobal->trace("Saving translations, language: %s", language);
+	JsonNode data(JsonNode::JsonType::DATA_STRUCT);
+	
+	mapHeader->jsonSerialize(data);
+	
+	addToArchive(data, language + ".json");
+}
 
 VCMI_LIB_NAMESPACE_END

+ 11 - 0
lib/mapping/MapFormatJson.h

@@ -202,6 +202,11 @@ public:
 	 * Reads complete map.
 	 */
 	void readMap();
+	
+	/**
+	 * Reads texts and translations
+	 */
+	void readTranslations();
 
 	static void readTerrainTile(const std::string & src, TerrainTile & tile);
 
@@ -214,6 +219,7 @@ public:
 	 */
 	void readObjects();
 
+	bool isExistArchive(const std::string & archiveFilename);
 	JsonNode getFromArchive(const std::string & archiveFilename);
 
 private:
@@ -249,6 +255,11 @@ public:
 	 * Saves header to zip archive
 	 */
 	void writeHeader();
+	
+	/**
+	 * Saves texts and translations to zip archive
+	 */
+	void writeTranslations(const std::string & language);
 
 	/**
 	 * Encodes one tile into string