瀏覽代碼

Json Serializer should now use identifers storage properly

Ivan Savenko 2 年之前
父節點
當前提交
b6a1a8f0da

+ 43 - 18
lib/constants/EntityIdentifiers.cpp

@@ -115,6 +115,11 @@ std::string HeroTypeID::encode(const si32 index)
 	return VLC->heroTypes()->getByIndex(index)->getJsonKey();
 }
 
+std::string HeroTypeID::entityType()
+{
+	return "hero";
+}
+
 const CArtifact * ArtifactIDBase::toArtifact() const
 {
 	return dynamic_cast<const CArtifact*>(toArtifact(VLC->artifacts()));
@@ -125,7 +130,7 @@ const Artifact * ArtifactIDBase::toArtifact(const ArtifactService * service) con
 	return service->getByIndex(num);
 }
 
-si32 ArtifactIDBase::decode(const std::string & identifier)
+si32 ArtifactID::decode(const std::string & identifier)
 {
 	auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), "artifact", identifier);
 	if(rawId)
@@ -134,11 +139,16 @@ si32 ArtifactIDBase::decode(const std::string & identifier)
 		return -1;
 }
 
-std::string ArtifactIDBase::encode(const si32 index)
+std::string ArtifactID::encode(const si32 index)
 {
 	return VLC->artifacts()->getByIndex(index)->getJsonKey();
 }
 
+std::string ArtifactID::entityType()
+{
+	return "artifact";
+}
+
 const CCreature * CreatureIDBase::toCreature() const
 {
 	return VLC->creh->objects.at(num);
@@ -149,7 +159,7 @@ const Creature * CreatureIDBase::toCreature(const CreatureService * creatures) c
 	return creatures->getByIndex(num);
 }
 
-si32 CreatureIDBase::decode(const std::string & identifier)
+si32 CreatureID::decode(const std::string & identifier)
 {
 	auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), "creature", identifier);
 	if(rawId)
@@ -158,11 +168,16 @@ si32 CreatureIDBase::decode(const std::string & identifier)
 		return -1;
 }
 
-std::string CreatureIDBase::encode(const si32 index)
+std::string CreatureID::encode(const si32 index)
 {
 	return VLC->creatures()->getById(CreatureID(index))->getJsonKey();
 }
 
+std::string CreatureID::entityType()
+{
+	return "creature";
+}
+
 const CSpell * SpellIDBase::toSpell() const
 {
 	if(num < 0 || num >= VLC->spellh->objects.size())
@@ -178,7 +193,7 @@ const spells::Spell * SpellIDBase::toSpell(const spells::Service * service) cons
 	return service->getByIndex(num);
 }
 
-si32 SpellIDBase::decode(const std::string & identifier)
+si32 SpellID::decode(const std::string & identifier)
 {
 	auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), "spell", identifier);
 	if(rawId)
@@ -187,11 +202,16 @@ si32 SpellIDBase::decode(const std::string & identifier)
 		return -1;
 }
 
-std::string SpellIDBase::encode(const si32 index)
+std::string SpellID::encode(const si32 index)
 {
 	return VLC->spells()->getByIndex(index)->getJsonKey();
 }
 
+std::string SpellID::entityType()
+{
+	return "spell";
+}
+
 bool PlayerColor::isValidPlayer() const
 {
 	return num >= 0 && num < PLAYER_LIMIT_I;
@@ -199,15 +219,15 @@ bool PlayerColor::isValidPlayer() const
 
 bool PlayerColor::isSpectator() const
 {
-	return num == SPECTATOR.num;
-}
-
-std::string PlayerColor::toString() const
-{
-	return encode(num);
-}
-
-si32 PlayerColor::decode(const std::string & identifier)
+	return num == SPECTATOR.num;
+}
+
+std::string PlayerColor::toString() const
+{
+	return encode(num);
+}
+
+si32 PlayerColor::decode(const std::string & identifier)
 {
 	return vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, identifier);
 }
@@ -217,6 +237,11 @@ std::string PlayerColor::encode(const si32 index)
 	return GameConstants::PLAYER_COLOR_NAMES[index];
 }
 
+std::string PlayerColor::entityType()
+{
+	return "playerColor";
+}
+
 si32 FactionID::decode(const std::string & identifier)
 {
 	auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), entityType(), identifier);
@@ -236,7 +261,7 @@ std::string FactionID::entityType()
 	return "faction";
 }
 
-si32 TerrainIdBase::decode(const std::string & identifier)
+si32 TerrainId::decode(const std::string & identifier)
 {
 	auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), entityType(), identifier);
 	if(rawId)
@@ -245,12 +270,12 @@ si32 TerrainIdBase::decode(const std::string & identifier)
 		return static_cast<si32>(TerrainId::NONE);
 }
 
-std::string TerrainIdBase::encode(const si32 index)
+std::string TerrainId::encode(const si32 index)
 {
 	return VLC->terrainTypeHandler->getByIndex(index)->getJsonKey();
 }
 
-std::string TerrainIdBase::entityType()
+std::string TerrainId::entityType()
 {
 	return "terrain";
 }

+ 31 - 26
lib/constants/EntityIdentifiers.h

@@ -200,6 +200,7 @@ public:
 	///json serialization helpers
 	static si32 decode(const std::string & identifier);
 	static std::string encode(const si32 index);
+	static std::string entityType();
 
 	DLL_LINKAGE static const HeroTypeID NONE;
 };
@@ -236,16 +237,17 @@ public:
 	static const PlayerColor NEUTRAL; //255
 	static const PlayerColor PLAYER_LIMIT; //player limit per map
 
-	bool isValidPlayer() const; //valid means < PLAYER_LIMIT (especially non-neutral)
-	bool isSpectator() const;
-
-	std::string toString() const;
-
-	static si32 decode(const std::string& identifier);
-	static std::string encode(const si32 index);
-};
-
-class TeamID : public Identifier<TeamID>
+	bool isValidPlayer() const; //valid means < PLAYER_LIMIT (especially non-neutral)
+	bool isSpectator() const;
+
+	std::string toString() const;
+
+	static si32 decode(const std::string& identifier);
+	static std::string encode(const si32 index);
+	static std::string entityType();
+};
+
+class TeamID : public Identifier<TeamID>
 {
 public:
 	using Identifier<TeamID>::Identifier;
@@ -627,16 +629,17 @@ public:
 
 	DLL_LINKAGE const CArtifact * toArtifact() const;
 	DLL_LINKAGE const Artifact * toArtifact(const ArtifactService * service) const;
-
-	///json serialization helpers
-	static si32 decode(const std::string & identifier);
-	static std::string encode(const si32 index);
 };
 
 class ArtifactID : public IdentifierWithEnum<ArtifactID, ArtifactIDBase>
 {
 public:
 	using IdentifierWithEnum<ArtifactID, ArtifactIDBase>::IdentifierWithEnum;
+
+	///json serialization helpers
+	static si32 decode(const std::string & identifier);
+	static std::string encode(const si32 index);
+	static std::string entityType();
 };
 
 class CreatureIDBase : public IdentifierBase
@@ -666,16 +669,17 @@ public:
 
 	DLL_LINKAGE const CCreature * toCreature() const;
 	DLL_LINKAGE const Creature * toCreature(const CreatureService * creatures) const;
-
-	///json serialization helpers
-	static si32 decode(const std::string & identifier);
-	static std::string encode(const si32 index);
 };
 
 class CreatureID : public IdentifierWithEnum<CreatureID, CreatureIDBase>
 {
 public:
 	using IdentifierWithEnum<CreatureID, CreatureIDBase>::IdentifierWithEnum;
+
+	///json serialization helpers
+	static si32 decode(const std::string & identifier);
+	static std::string encode(const si32 index);
+	static std::string entityType();
 };
 
 class SpellIDBase : public IdentifierBase
@@ -783,16 +787,17 @@ public:
 
 	DLL_LINKAGE const CSpell * toSpell() const; //deprecated
 	DLL_LINKAGE const spells::Spell * toSpell(const spells::Service * service) const;
-
-	///json serialization helpers
-	static si32 decode(const std::string & identifier);
-	static std::string encode(const si32 index);
 };
 
 class SpellID : public IdentifierWithEnum<SpellID, SpellIDBase>
 {
 public:
 	using IdentifierWithEnum<SpellID, SpellIDBase>::IdentifierWithEnum;
+
+	///json serialization helpers
+	static si32 decode(const std::string & identifier);
+	static std::string encode(const si32 index);
+	static std::string entityType();
 };
 
 class BattleFieldInfo;
@@ -837,16 +842,16 @@ public:
 		ROCK,
 		ORIGINAL_REGULAR_TERRAIN_COUNT = ROCK
 	};
-
-	static si32 decode(const std::string & identifier);
-	static std::string encode(const si32 index);
-	static std::string entityType();
 };
 
 class TerrainId : public IdentifierWithEnum<TerrainId, TerrainIdBase>
 {
 public:
 	using IdentifierWithEnum<TerrainId, TerrainIdBase>::IdentifierWithEnum;
+
+	static si32 decode(const std::string & identifier);
+	static std::string encode(const si32 index);
+	static std::string entityType();
 };
 
 class ObstacleInfo;

+ 18 - 31
lib/rmg/CRmgTemplate.cpp

@@ -65,35 +65,6 @@ void CTreasureInfo::serializeJson(JsonSerializeFormat & handler)
 namespace rmg
 {
 
-//FIXME: This is never used, instead TerrainID is used
-class TerrainEncoder
-{
-public:
-	static si32 decode(const std::string & identifier)
-	{
-		return *VLC->identifiers()->getIdentifier(ModScope::scopeGame(), "terrain", identifier);
-	}
-
-	static std::string encode(const si32 index)
-	{
-		return VLC->terrainTypeHandler->getByIndex(index)->getJsonKey();
-	}
-};
-
-class ZoneEncoder
-{
-public:
-	static si32 decode(const std::string & json)
-	{
-		return std::stoi(json);
-	}
-
-	static std::string encode(si32 id)
-	{
-		return std::to_string(id);
-	}
-};
-
 const TRmgTemplateZoneId ZoneOptions::NO_ZONE = -1;
 
 ZoneOptions::CTownInfo::CTownInfo()
@@ -508,8 +479,24 @@ void ZoneConnection::serializeJson(JsonSerializeFormat & handler)
 		"random"
 	};
 
-	handler.serializeId<TRmgTemplateZoneId, TRmgTemplateZoneId, ZoneEncoder>("a", zoneA, -1);
-	handler.serializeId<TRmgTemplateZoneId, TRmgTemplateZoneId, ZoneEncoder>("b", zoneB, -1);
+	if (handler.saving)
+	{
+		std::string zoneNameA = std::to_string(zoneA);
+		std::string zoneNameB = std::to_string(zoneB);
+		handler.serializeString("a", zoneNameA);
+		handler.serializeString("b", zoneNameB);
+	}
+	else
+	{
+		std::string zoneNameA;
+		std::string zoneNameB;
+		handler.serializeString("a", zoneNameA);
+		handler.serializeString("b", zoneNameB);
+
+		zoneA = std::stoi(zoneNameA);
+		zoneB = std::stoi(zoneNameB);
+	}
+
 	handler.serializeInt("guard", guardStrength, 0);
 	handler.serializeEnum("type", connectionType, connectionTypes);
 	handler.serializeEnum("road", hasRoad, roadOptions);

+ 14 - 0
lib/serializer/JsonDeserializer.cpp

@@ -107,6 +107,20 @@ void JsonDeserializer::serializeInternal(const std::string & fieldName, si32 & v
 		value = rawValue;
 }
 
+void JsonDeserializer::serializeInternal(const std::string & fieldName, std::vector<std::string> & value)
+{
+	const JsonVector & data = currentObject->operator[](fieldName).Vector();
+
+	value.clear();
+	value.reserve(data.size());
+
+	for(const JsonNode& elem : data)
+	{
+		std::string rawId = elem.String();
+		value.push_back(rawId);
+	}
+}
+
 void JsonDeserializer::serializeInternal(std::string & value)
 {
 	value = currentObject->String();

+ 1 - 0
lib/serializer/JsonDeserializer.h

@@ -33,6 +33,7 @@ protected:
 	void serializeInternal(const std::string & fieldName, double & value, const std::optional<double> & defaultValue) override;
 	void serializeInternal(const std::string & fieldName, si64 & value, const std::optional<si64> & defaultValue) override;
 	void serializeInternal(const std::string & fieldName, si32 & value, const std::optional<si32> & defaultValue, const std::vector<std::string> & enumMap) override;
+	void serializeInternal(const std::string & fieldName, std::vector<std::string> & value) override;
 
 	void serializeInternal(std::string & value) override;
 	void serializeInternal(int64_t & value) override;

+ 56 - 34
lib/serializer/JsonSerializeFormat.h

@@ -11,6 +11,7 @@
 
 #include "../JsonNode.h"
 #include "../modding/IdentifierStorage.h"
+#include "../modding/ModScope.h"
 #include "../VCMI_Lib.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
@@ -271,36 +272,57 @@ public:
 	template <typename T, typename U, typename E = T>
 	void serializeId(const std::string & fieldName, T & value, const U & defaultValue)
 	{
-		doSerializeInternal<T, U, si32>(fieldName, value, defaultValue, &E::decode, &E::encode);
+		if (saving)
+		{
+			if (value != defaultValue)
+			{
+				std::string fieldValue = E::encode(value);
+				serializeString(fieldName, fieldValue);
+			}
+		}
+		else
+		{
+			std::string fieldValue;
+			serializeString(fieldName, fieldValue);
+
+			if (!fieldValue.empty())
+			{
+				VLC->identifiers()->requestIdentifier(ModScope::scopeGame(), E::entityType(), fieldValue, [&value](int32_t index){
+					value = T(index);
+				});
+			}
+			else
+			{
+				value = T(defaultValue);
+			}
+		}
 	}
 
 	///si32-convertible identifier vector <-> Json array of string
 	template <typename T, typename E = T>
 	void serializeIdArray(const std::string & fieldName, std::vector<T> & value)
 	{
-		std::vector<si32> temp;
-
-		if(saving)
+		if (saving)
 		{
-			temp.reserve(value.size());
+			std::vector<std::string> fieldValue;
 
 			for(const T & vitem : value)
-			{
-				si32 item = static_cast<si32>(vitem);
-				temp.push_back(item);
-			}
-		}
+				fieldValue.push_back(E::encode(vitem));
 
-		serializeInternal(fieldName, temp, &E::decode, &E::encode);
-		if(!saving)
+			serializeInternal(fieldName, fieldValue);
+		}
+		else
 		{
-			value.clear();
-			value.reserve(temp.size());
+			std::vector<std::string> fieldValue;
+			serializeInternal(fieldName, fieldValue);
+
+			value.resize(fieldValue.size());
 
-			for(const si32 item : temp)
+			for(size_t i = 0; i < fieldValue.size(); ++i)
 			{
-				T vitem = static_cast<T>(item);
-				value.push_back(vitem);
+				VLC->identifiers()->requestIdentifier(ModScope::scopeGame(), E::entityType(), fieldValue[i], [&value, i](int32_t index){
+					value[i] = T(index);
+				});
 			}
 		}
 	}
@@ -309,28 +331,25 @@ public:
 	template <typename T, typename U = T>
 	void serializeIdArray(const std::string & fieldName, std::set<T> & value)
 	{
-		std::vector<si32> temp;
-
-		if(saving)
+		if (saving)
 		{
-			temp.reserve(value.size());
+			std::vector<std::string> fieldValue;
 
 			for(const T & vitem : value)
-			{
-				si32 item = static_cast<si32>(vitem);
-				temp.push_back(item);
-			}
-		}
+				fieldValue.push_back(U::encode(vitem));
 
-		serializeInternal(fieldName, temp, &U::decode, &U::encode);
-		if(!saving)
+			serializeInternal(fieldName, fieldValue);
+		}
+		else
 		{
-			value.clear();
+			std::vector<std::string> fieldValue;
+			serializeInternal(fieldName, fieldValue);
 
-			for(const si32 item : temp)
+			for(size_t i = 0; i < fieldValue.size(); ++i)
 			{
-				T vitem = static_cast<T>(item);
-				value.insert(vitem);
+				VLC->identifiers()->requestIdentifier(ModScope::scopeGame(), U::entityType(), fieldValue[i], [&value](int32_t index){
+					value.insert(T(index));
+				});
 			}
 		}
 	}
@@ -340,9 +359,9 @@ public:
 	void serializeInstance(const std::string & fieldName, T & value, const T & defaultValue)
 	{
 		const TDecoder decoder = std::bind(&IInstanceResolver::decode, instanceResolver, _1);
-		const TEncoder endoder = std::bind(&IInstanceResolver::encode, instanceResolver, _1);
+		const TEncoder encoder = std::bind(&IInstanceResolver::encode, instanceResolver, _1);
 
-		serializeId<T>(fieldName, value, defaultValue, decoder, endoder);
+		serializeId<T>(fieldName, value, defaultValue, decoder, encoder);
 	}
 
 	///any serializable object <-> Json struct
@@ -376,6 +395,9 @@ protected:
 	///Enum/Numeric <-> Json string enum
 	virtual void serializeInternal(const std::string & fieldName, si32 & value, const std::optional<si32> & defaultValue, const std::vector<std::string> & enumMap) = 0;
 
+	///String vector <-> Json string vector
+	virtual void serializeInternal(const std::string & fieldName, std::vector<std::string> & value) = 0;
+
 	virtual void pop() = 0;
 	virtual void pushStruct(const std::string & fieldName) = 0;
 	virtual void pushArray(const std::string & fieldName) = 0;

+ 19 - 3
lib/serializer/JsonSerializer.cpp

@@ -63,9 +63,25 @@ void JsonSerializer::serializeInternal(const std::string & fieldName, std::vecto
 
 	for(const si32 rawId : value)
 	{
-        JsonNode jsonElement(JsonNode::JsonType::DATA_STRING);
-        jsonElement.String() = encoder(rawId);
-        data.push_back(std::move(jsonElement));
+		JsonNode jsonElement(JsonNode::JsonType::DATA_STRING);
+		jsonElement.String() = encoder(rawId);
+		data.push_back(std::move(jsonElement));
+	}
+}
+
+void JsonSerializer::serializeInternal(const std::string & fieldName, std::vector<std::string> & value)
+{
+	if(value.empty())
+		return;
+
+	JsonVector & data = currentObject->operator[](fieldName).Vector();
+	data.reserve(value.size());
+
+	for(const auto & rawId : value)
+	{
+		JsonNode jsonElement(JsonNode::JsonType::DATA_STRING);
+		jsonElement.String() = rawId;
+		data.push_back(std::move(jsonElement));
 	}
 }
 

+ 1 - 0
lib/serializer/JsonSerializer.h

@@ -32,6 +32,7 @@ protected:
 	void serializeInternal(const std::string & fieldName, double & value, const std::optional<double> & defaultValue) override;
 	void serializeInternal(const std::string & fieldName, si64 & value, const std::optional<si64> & defaultValue) override;
 	void serializeInternal(const std::string & fieldName, si32 & value, const std::optional<si32> & defaultValue, const std::vector<std::string> & enumMap) override;
+	void serializeInternal(const std::string & fieldName, std::vector<std::string> & value) override;
 
 	void serializeInternal(std::string & value) override;
 	void serializeInternal(int64_t & value) override;

+ 5 - 0
lib/serializer/JsonUpdater.cpp

@@ -61,6 +61,11 @@ void JsonUpdater::serializeInternal(const std::string & fieldName, std::vector<s
 //	}
 }
 
+void JsonUpdater::serializeInternal(const std::string & fieldName, std::vector<std::string> & value)
+{
+	// TODO
+}
+
 void JsonUpdater::serializeInternal(const std::string & fieldName, double & value, const std::optional<double> & defaultValue)
 {
 	const JsonNode & data = currentObject->operator[](fieldName);

+ 1 - 0
lib/serializer/JsonUpdater.h

@@ -37,6 +37,7 @@ protected:
 	void serializeInternal(const std::string & fieldName, double & value, const std::optional<double> & defaultValue) override;
 	void serializeInternal(const std::string & fieldName, si64 & value, const std::optional<si64> & defaultValue) override;
 	void serializeInternal(const std::string & fieldName, si32 & value, const std::optional<si32> & defaultValue, const std::vector<std::string> & enumMap) override;
+	void serializeInternal(const std::string & fieldName, std::vector<std::string> & value) override;
 
 	void serializeInternal(std::string & value) override;
 	void serializeInternal(int64_t & value) override;