From 52e56693ea1353c29ac624dacc35d5a5b5a904f8 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 3 Apr 2013 13:39:46 +0000 Subject: [PATCH] - fixed handling of incorrect configuration in settings.json - more compact schema for siege node --- config/schemas/townSiege.json | 357 +++++++--------------------------- lib/JsonNode.cpp | 65 +++++-- 2 files changed, 116 insertions(+), 306 deletions(-) diff --git a/config/schemas/townSiege.json b/config/schemas/townSiege.json index 5f4453c9c..e6c633580 100644 --- a/config/schemas/townSiege.json +++ b/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" } } } diff --git a/lib/JsonNode.cpp b/lib/JsonNode.cpp index 26cf48c70..c850c2440 100644 --- a/lib/JsonNode.cpp +++ b/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 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 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; }