Browse Source

- fixed handling of incorrect configuration in settings.json
- more compact schema for siege node

Ivan Savenko 12 years ago
parent
commit
52e56693ea
2 changed files with 116 additions and 306 deletions
  1. 70 287
      config/schemas/townSiege.json
  2. 46 19
      lib/JsonNode.cpp

+ 70 - 287
config/schemas/townSiege.json

@@ -1,347 +1,130 @@
 {
 	"type":"object",
 	"$schema": "http://json-schema.org/draft-04/schema",
-	"title" : "VCMI town building format",
-	"description" : "Format used to define town buildings in VCMI",
-	"id": "#",
+	"title" : "VCMI siege screen format",
+	"description" : "Format used to define town siege screen in VCMI",
+	"required" : [
+		"gate", "imagePrefix", "moat", "shooterHeight", "shooter",
+		"static", "towers", "walls"
+	 ],
+	
+	"definitions" :
+	{
+		"point" : {
+			"type" : "object",
+			"required" : [ "x", "y" ],
+			"properties":{
+				"x": { "type":"number" },
+				"y": { "type":"number" }
+			}
+		},
+		"tower" : {
+			"type" : "object",
+			"required" : [ "battlement", "creature", "tower" ],
+			"properties":{
+				"battlement": {
+					"description" : "Location of battlement, part of tower that covers shooter",
+					"$ref" : "#/definitions/point"
+				},
+				"creature": {
+					"description" : "Location of shooter in tower",
+					"$ref" : "#/definitions/point"
+				},
+				"tower": {
+					"description" : "Location of main segment of tower",
+					"$ref" : "#/definitions/point"
+				}
+			}
+		}
+	},
+
 	"properties":{
 		"gate": {
 			"type":"object",
-			"id": "gate",
+			"description" : "Town gates",
 			"properties":{
 				"arch": {
-					"type":"object",
-					"id": "arch",
-					"properties":{
-						"x": {
-							"type":"number",
-							"id": "x"
-						},
-						"y": {
-							"type":"number",
-							"id": "y"
-						}
-					}
+					"description" : "Static, top part of gates",
+					"$ref" : "#/definitions/point"
 				},
 				"gate": {
-					"type":"object",
-					"id": "gate",
-					"properties":{
-						"x": {
-							"type":"number",
-							"id": "x"
-						},
-						"y": {
-							"type":"number",
-							"id": "y"
-						}
-					}
+					"description" : "Main section of gates",
+					"$ref" : "#/definitions/point"
 				}
 			}
 		},
 		"imagePrefix": {
 			"type":"string",
-			"id": "imagePrefix"
+			"description" : "Prefix to all images related to siege screen"
 		},
 		"moat": {
 			"type":"object",
-			"id": "moat",
+			"description" : "Castle moat description",
 			"properties":{
 				"bank": {
-					"type":"object",
-					"id": "bank",
-					"properties":{
-						"x": {
-							"type":"number",
-							"id": "x"
-						},
-						"y": {
-							"type":"number",
-							"id": "y"
-						}
-					}
+					"description" : "Small section with bank of the moat",
+					"$ref" : "#/definitions/point"
 				},
 				"moat": {
-					"type":"object",
-					"id": "moat",
-					"properties":{
-						"x": {
-							"type":"number",
-							"id": "x"
-						},
-						"y": {
-							"type":"number",
-							"id": "y"
-						}
-					}
+					"description" : "Main section of the moat",
+					"$ref" : "#/definitions/point"
 				}
 			}
 		},
 		"shooterHeight": {
 			"type":"number",
-			"id": "shooterHeight"
+			"description" : "Height at which shooter image will be cropped"
 		},
 		"shooter": {
 			"type":"string",
-			"id": "shooter"
+			"description" : "Identifier of creature that will be used as tower shooter"
 		},
 		"static": {
 			"type":"object",
-			"id": "static",
+			"description" : "Static sections of walls",
 			"properties":{
 				"background": {
-					"type":"object",
-					"id": "background",
-					"properties":{
-						"x": {
-							"type":"number",
-							"id": "x"
-						},
-						"y": {
-							"type":"number",
-							"id": "y"
-						}
-					}
+					"description" : "Very top section of the wall located above hero",
+					"$ref" : "#/definitions/point"
 				},
 				"bottom": {
-					"type":"object",
-					"id": "bottom",
-					"properties":{
-						"x": {
-							"type":"number",
-							"id": "x"
-						},
-						"y": {
-							"type":"number",
-							"id": "y"
-						}
-					}
+					"description" : "Bottom section located between destructible sections",
+					"$ref" : "#/definitions/point"
 				},
 				"top": {
-					"type":"object",
-					"id": "top",
-					"properties":{
-						"x": {
-							"type":"number",
-							"id": "x"
-						},
-						"y": {
-							"type":"number",
-							"id": "y"
-						}
-					}
+					"description" : "Top section located between destructible sections",
+					"$ref" : "#/definitions/point"
 				}
 			}
 		},
 		"towers": {
 			"type":"object",
-			"id": "towers",
+			"description" : "Decription of towers",
 			"properties":{
-				"bottom": {
-					"type":"object",
-					"id": "bottom",
-					"properties":{
-						"battlement": {
-							"type":"object",
-							"id": "battlement",
-							"properties":{
-								"x": {
-									"type":"number",
-									"id": "x"
-								},
-								"y": {
-									"type":"number",
-									"id": "y"
-								}
-							}
-						},
-						"creature": {
-							"type":"object",
-							"id": "creature",
-							"properties":{
-								"x": {
-									"type":"number",
-									"id": "x"
-								},
-								"y": {
-									"type":"number",
-									"id": "y"
-								}
-							}
-						},
-						"tower": {
-							"type":"object",
-							"id": "tower",
-							"properties":{
-								"x": {
-									"type":"number",
-									"id": "x"
-								},
-								"y": {
-									"type":"number",
-									"id": "y"
-								}
-							}
-						}
-					}
-				},
-				"keep": {
-					"type":"object",
-					"id": "keep",
-					"properties":{
-						"battlement": {
-							"type":"object",
-							"id": "battlement",
-							"properties":{
-								"x": {
-									"type":"number",
-									"id": "x"
-								},
-								"y": {
-									"type":"number",
-									"id": "y"
-								}
-							}
-						},
-						"creature": {
-							"type":"object",
-							"id": "creature",
-							"properties":{
-								"x": {
-									"type":"number",
-									"id": "x"
-								},
-								"y": {
-									"type":"number",
-									"id": "y"
-								}
-							}
-						},
-						"tower": {
-							"type":"object",
-							"id": "tower",
-							"properties":{
-								"x": {
-									"type":"number",
-									"id": "x"
-								},
-								"y": {
-									"type":"number",
-									"id": "y"
-								}
-							}
-						}
-					}
-				},
-				"top": {
-					"type":"object",
-					"id": "top",
-					"properties":{
-						"battlement": {
-							"type":"object",
-							"id": "battlement",
-							"properties":{
-								"x": {
-									"type":"number",
-									"id": "x"
-								},
-								"y": {
-									"type":"number",
-									"id": "y"
-								}
-							}
-						},
-						"creature": {
-							"type":"object",
-							"id": "creature",
-							"properties":{
-								"x": {
-									"type":"number",
-									"id": "x"
-								},
-								"y": {
-									"type":"number",
-									"id": "y"
-								}
-							}
-						},
-						"tower": {
-							"type":"object",
-							"id": "tower",
-							"properties":{
-								"x": {
-									"type":"number",
-									"id": "x"
-								},
-								"y": {
-									"type":"number",
-									"id": "y"
-								}
-							}
-						}
-					}
-				}
+				"bottom": { "$ref" : "#/definitions/tower", "description" : "Bottom tower" },
+				"keep":   { "$ref" : "#/definitions/tower", "description" : "Central keep" },
+				"top":    { "$ref" : "#/definitions/tower", "description" : "Top tower" }
 			}
 		},
 		"walls": {
 			"type":"object",
-			"id": "walls",
+			"description" : "Destructible sections of the walls",
 			"properties":{
 				"bottomMid": {
-					"type":"object",
-					"id": "bottomMid",
-					"properties":{
-						"x": {
-							"type":"number",
-							"id": "x"
-						},
-						"y": {
-							"type":"number",
-							"id": "y"
-						}
-					}
+					"description" : "Second from bottom section located near gates",
+					"$ref" : "#/definitions/point"
 				},
 				"bottom": {
-					"type":"object",
-					"id": "bottom",
-					"properties":{
-						"x": {
-							"type":"number",
-							"id": "x"
-						},
-						"y": {
-							"type":"number",
-							"id": "y"
-						}
-					}
+					"description" : "Bottommost section located near bottom tower",
+					"$ref" : "#/definitions/point"
 				},
 				"upperMid": {
-					"type":"object",
-					"id": "upperMid",
-					"properties":{
-						"x": {
-							"type":"number",
-							"id": "x"
-						},
-						"y": {
-							"type":"number",
-							"id": "y"
-						}
-					}
+					"description" : "Second from top section located near gates",
+					"$ref" : "#/definitions/point"
 				},
 				"upper": {
-					"type":"object",
-					"id": "upper",
-					"properties":{
-						"x": {
-							"type":"number",
-							"id": "x"
-						},
-						"y": {
-							"type":"number",
-							"id": "y"
-						}
-					}
+					"description" : "Topmost section located near top tower",
+					"$ref" : "#/definitions/point"
 				}
 			}
 		}

+ 46 - 19
lib/JsonNode.cpp

@@ -1367,19 +1367,31 @@ void JsonUtils::unparseBonus( JsonNode &node, const Bonus * bonus )
 
 void minimizeNode(JsonNode & node, const JsonNode & schema)
 {
-	assert(schema["type"].String() == "object");
-
-	BOOST_FOREACH(auto & entry, schema["required"].Vector())
+	if (schema["type"].String() == "object")
 	{
-		std::string name = entry.String();
+		std::set<std::string> foundEntries;
+
+		BOOST_FOREACH(auto & entry, schema["required"].Vector())
+		{
+			std::string name = entry.String();
+			foundEntries.insert(name);
 
-		if (node[name].getType() == JsonNode::DATA_STRUCT)
 			minimizeNode(node[name], schema["properties"][name]);
 
-		if (vstd::contains(node.Struct(), name) &&
-		    node[name] == schema["properties"][name]["default"])
+			if (vstd::contains(node.Struct(), name) &&
+				node[name] == schema["properties"][name]["default"])
+			{
+				node.Struct().erase(name);
+			}
+		}
+
+		// erase all unhandled entries
+		for (auto it = node.Struct().begin(); it != node.Struct().end();)
 		{
-			node.Struct().erase(name);
+			if (!vstd::contains(foundEntries, it->first))
+				it = node.Struct().erase(it);
+			else
+				it++;
 		}
 	}
 }
@@ -1389,21 +1401,36 @@ void JsonUtils::minimize(JsonNode & node, std::string schemaName)
 	minimizeNode(node, getSchema(schemaName));
 }
 
+// FIXME: except for several lines function is identical to minimizeNode. Some way to reduce duplication?
 void maximizeNode(JsonNode & node, const JsonNode & schema)
 {
-	assert(schema["type"].String() == "object");
-
-	BOOST_FOREACH(auto & entry, schema["required"].Vector())
+	// "required" entry can only be found in object/struct
+	if (schema["type"].String() == "object")
 	{
-		std::string name = entry.String();
+		std::set<std::string> foundEntries;
 
-		if (node[name].isNull() &&
-		    !schema["properties"][name]["default"].isNull())
+		// check all required entries that have default version
+		BOOST_FOREACH(auto & entry, schema["required"].Vector())
 		{
-			node[name] = schema["properties"][name]["default"];
-		}
-		if (node[name].getType() == JsonNode::DATA_STRUCT)
+			std::string name = entry.String();
+			foundEntries.insert(name);
+
+			if (node[name].isNull() &&
+				!schema["properties"][name]["default"].isNull())
+			{
+				node[name] = schema["properties"][name]["default"];
+			}
 			maximizeNode(node[name], schema["properties"][name]);
+		}
+
+		// erase all unhandled entries
+		for (auto it = node.Struct().begin(); it != node.Struct().end();)
+		{
+			if (!vstd::contains(foundEntries, it->first))
+				it = node.Struct().erase(it);
+			else
+				it++;
+		}
 	}
 }
 
@@ -1434,7 +1461,7 @@ const JsonNode & getSchemaByName(std::string name)
 		return loadedSchemas[name];
 	}
 
-	tlog0 << "Error: missing schema with name " << name << "!\n";
+	tlog1 << "Error: missing schema with name " << name << "!\n";
 	assert(0);
 	return nullNode;
 }
@@ -1449,7 +1476,7 @@ const JsonNode & JsonUtils::getSchema(std::string URI)
 
 	if (segments[0] != "vcmi")
 	{
-		tlog0 << "Error: unsupported URI protocol for schema: " << segments[0] << "\n";
+		tlog1 << "Error: unsupported URI protocol for schema: " << segments[0] << "\n";
 		return nullNode;
 	}