Explorar o código

Analyze json object modifications to detect mod conflicts

Ivan Savenko hai 1 ano
pai
achega
d0aba56a5e
Modificáronse 3 ficheiros con 35 adicións e 0 borrados
  1. 28 0
      lib/json/JsonUtils.cpp
  2. 4 0
      lib/json/JsonUtils.h
  3. 3 0
      lib/modding/ContentTypeHandler.cpp

+ 28 - 0
lib/json/JsonUtils.cpp

@@ -275,4 +275,32 @@ JsonNode JsonUtils::assembleFromFiles(const std::string & filename)
 	return result;
 }
 
+void JsonUtils::detectConflicts(const JsonNode & left, const JsonNode & right, const std::string & entityName, const std::string & keyName)
+{
+	if (left == right)
+		return;
+
+	switch (left.getType())
+	{
+		case JsonNode::JsonType::DATA_NULL:
+		case JsonNode::JsonType::DATA_BOOL:
+		case JsonNode::JsonType::DATA_FLOAT:
+		case JsonNode::JsonType::DATA_INTEGER:
+		case JsonNode::JsonType::DATA_STRING:
+		case JsonNode::JsonType::DATA_VECTOR: // NOTE: comparing vectors as whole - since merge will overwrite it in its entirety
+		{
+			logMod->warn("Potential confict detected between '%s' and '%s' in object '%s'", left.getModScope(), right.getModScope(), entityName);
+			logMod->warn("Mod '%s' - value %s set to '%s'", left.getModScope(), keyName, left.toCompactString());
+			logMod->warn("Mod '%s' - value %s set to '%s'", right.getModScope(), keyName, right.toCompactString());
+			return;
+		}
+		case JsonNode::JsonType::DATA_STRUCT:
+		{
+			for(auto & node : left.Struct())
+				if (!right[node.first].isNull())
+					detectConflicts(node.second, right[node.first], entityName, keyName + "/" + node.first);
+		}
+	}
+}
+
 VCMI_LIB_NAMESPACE_END

+ 4 - 0
lib/json/JsonUtils.h

@@ -72,6 +72,10 @@ namespace JsonUtils
 	/// get schema by json URI: vcmi:<name of file in schemas directory>#<entry in file, optional>
 	/// example: schema "vcmi:settings" is used to check user settings
 	DLL_LINKAGE const JsonNode & getSchema(const std::string & URI);
+
+	/// detects potential conflicts - json entries present in both nodes
+	/// any error messages will be printed to error log
+	DLL_LINKAGE void detectConflicts(const JsonNode & left, const JsonNode & right, const std::string & entityName, const std::string & keyName);
 }
 
 VCMI_LIB_NAMESPACE_END

+ 3 - 0
lib/modding/ContentTypeHandler.cpp

@@ -79,6 +79,9 @@ bool ContentTypeHandler::preloadModData(const std::string & modName, const std::
 			logMod->trace("Patching object %s (%s) from %s", objectName, remoteName, modName);
 			JsonNode & remoteConf = modData[remoteName].patches[objectName];
 
+			if (!remoteConf.isNull())
+				JsonUtils::detectConflicts(remoteConf, entry.second, objectName, "<root>");
+
 			JsonUtils::merge(remoteConf, entry.second);
 		}
 	}