소스 검색

Configure JSON merge behaviour via #override flag (#423)

* added json flags; override flag affects how structs are merged
Henning Koehler 7 년 전
부모
커밋
4ee9d7f65a
4개의 변경된 파일47개의 추가작업 그리고 12개의 파일을 삭제
  1. 20 0
      lib/JsonDetail.cpp
  2. 17 8
      lib/JsonNode.cpp
  3. 9 3
      lib/JsonNode.h
  4. 1 1
      lib/serializer/CSerializer.h

+ 20 - 0
lib/JsonDetail.cpp

@@ -46,6 +46,8 @@ void JsonWriter::writeEntry(JsonMap::const_iterator entry)
 	{
 		if (!entry->second.meta.empty())
 			out << prefix << " // " << entry->second.meta << "\n";
+		if(!entry->second.flags.empty())
+			out << prefix << " // flags: " << boost::algorithm::join(entry->second.flags, ", ") << "\n";
 		out << prefix;
 	}
 	writeString(entry->first);
@@ -59,6 +61,8 @@ void JsonWriter::writeEntry(JsonVector::const_iterator entry)
 	{
 		if (!entry->meta.empty())
 			out << prefix << " // " << entry->meta << "\n";
+		if(!entry->flags.empty())
+			out << prefix << " // flags: " << boost::algorithm::join(entry->flags, ", ") << "\n";
 		out << prefix;
 	}
 	writeNode(*entry);
@@ -389,6 +393,18 @@ bool JsonParser::extractStruct(JsonNode &node)
 		if (!extractString(key))
 			return false;
 
+		// split key string into actual key and meta-flags
+		std::vector<std::string> keyAndFlags;
+		boost::split(keyAndFlags, key, boost::is_any_of("#"));
+		key = keyAndFlags[0];
+		// check for unknown flags - helps with debugging
+		std::vector<std::string> knownFlags = { "override" };
+		for(int i = 1; i < keyAndFlags.size(); i++)
+		{
+			if(!vstd::contains(knownFlags, keyAndFlags[i]))
+				error("Encountered unknown flag #" + keyAndFlags[i], true);
+		}
+
 		if (node.Struct().find(key) != node.Struct().end())
 			error("Dublicated element encountered!", true);
 
@@ -398,6 +414,10 @@ bool JsonParser::extractStruct(JsonNode &node)
 		if (!extractElement(node.Struct()[key], '}'))
 			return false;
 
+		// flags from key string belong to referenced element
+		for(int i = 1; i < keyAndFlags.size(); i++)
+			node.Struct()[key].flags.push_back(keyAndFlags[i]);
+
 		if (input[pos] == '}')
 		{
 			pos++;

+ 17 - 8
lib/JsonNode.cpp

@@ -70,7 +70,8 @@ JsonNode::JsonNode(ResourceID && fileURI, bool &isValidSyntax):
 
 JsonNode::JsonNode(const JsonNode &copy):
 	type(JsonType::DATA_NULL),
-	meta(copy.meta)
+	meta(copy.meta),
+	flags(copy.flags)
 {
 	setType(copy.getType());
 	switch(type)
@@ -96,6 +97,7 @@ void JsonNode::swap(JsonNode &b)
 	swap(meta, b.meta);
 	swap(data, b.data);
 	swap(type, b.type);
+	swap(flags, b.flags);
 }
 
 JsonNode & JsonNode::operator =(JsonNode node)
@@ -846,7 +848,7 @@ const JsonNode & JsonUtils::getSchema(std::string URI)
 		return getSchemaByName(filename).resolvePointer(URI.substr(posHash + 1));
 }
 
-void JsonUtils::merge(JsonNode & dest, JsonNode & source)
+void JsonUtils::merge(JsonNode & dest, JsonNode & source, bool noOverride)
 {
 	if (dest.getType() == JsonNode::JsonType::DATA_NULL)
 	{
@@ -872,23 +874,30 @@ void JsonUtils::merge(JsonNode & dest, JsonNode & source)
 		}
 		case JsonNode::JsonType::DATA_STRUCT:
 		{
-			//recursively merge all entries from struct
-			for(auto & node : source.Struct())
-				merge(dest[node.first], node.second);
+			if(!noOverride && vstd::contains(source.flags, "override"))
+			{
+				std::swap(dest, source);
+			}
+			else
+			{
+				//recursively merge all entries from struct
+				for(auto & node : source.Struct())
+					merge(dest[node.first], node.second, noOverride);
+			}
 		}
 	}
 }
 
-void JsonUtils::mergeCopy(JsonNode & dest, JsonNode source)
+void JsonUtils::mergeCopy(JsonNode & dest, JsonNode source, bool noOverride)
 {
 	// uses copy created in stack to safely merge two nodes
-	merge(dest, source);
+	merge(dest, source, noOverride);
 }
 
 void JsonUtils::inherit(JsonNode & descendant, const JsonNode & base)
 {
 	JsonNode inheritedNode(base);
-	merge(inheritedNode,descendant);
+	merge(inheritedNode, descendant, true);
 	descendant.swap(inheritedNode);
 }
 

+ 9 - 3
lib/JsonNode.h

@@ -45,8 +45,10 @@ private:
 	JsonData data;
 
 public:
-	/// free to use metadata field
+	/// free to use metadata fields
 	std::string meta;
+	// meta-flags like override
+	std::vector<std::string> flags;
 
 	//Create empty node
 	JsonNode(JsonType Type = JsonType::DATA_NULL);
@@ -119,6 +121,10 @@ public:
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & meta;
+		if(version >= 782)
+		{
+			h & flags;
+		}
 		h & type;
 		switch(type)
 		{
@@ -173,7 +179,7 @@ namespace JsonUtils
 	 * null   : if value in source is present but set to null it will delete entry in dest
 	 * @note this function will destroy data in source
 	 */
-	DLL_LINKAGE void merge(JsonNode & dest, JsonNode & source);
+	DLL_LINKAGE void merge(JsonNode & dest, JsonNode & source, bool noOverride = false);
 
 	/**
 	 * @brief recursively merges source into dest, replacing identical fields
@@ -183,7 +189,7 @@ namespace JsonUtils
 	 * null   : if value in source is present but set to null it will delete entry in dest
 	 * @note this function will preserve data stored in source by creating copy
 	 */
-	DLL_LINKAGE void mergeCopy(JsonNode & dest, JsonNode source);
+	DLL_LINKAGE void mergeCopy(JsonNode & dest, JsonNode source, bool noOverride = false);
 
     /** @brief recursively merges descendant into copy of base node
      * Result emulates inheritance semantic

+ 1 - 1
lib/serializer/CSerializer.h

@@ -12,7 +12,7 @@
 #include "../ConstTransitivePtr.h"
 #include "../GameConstants.h"
 
-const ui32 SERIALIZATION_VERSION = 781;
+const ui32 SERIALIZATION_VERSION = 782;
 const ui32 MINIMAL_SERIALIZATION_VERSION = 753;
 const std::string SAVEGAME_MAGIC = "VCMISVG";