1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-21 00:19:29 +02:00

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

* added json flags; override flag affects how structs are merged
This commit is contained in:
Henning Koehler
2018-03-05 16:30:10 +13:00
committed by ArseniyShestakov
parent f126a34a5e
commit 4ee9d7f65a
4 changed files with 47 additions and 12 deletions

View File

@ -46,6 +46,8 @@ void JsonWriter::writeEntry(JsonMap::const_iterator entry)
{ {
if (!entry->second.meta.empty()) if (!entry->second.meta.empty())
out << prefix << " // " << entry->second.meta << "\n"; out << prefix << " // " << entry->second.meta << "\n";
if(!entry->second.flags.empty())
out << prefix << " // flags: " << boost::algorithm::join(entry->second.flags, ", ") << "\n";
out << prefix; out << prefix;
} }
writeString(entry->first); writeString(entry->first);
@ -59,6 +61,8 @@ void JsonWriter::writeEntry(JsonVector::const_iterator entry)
{ {
if (!entry->meta.empty()) if (!entry->meta.empty())
out << prefix << " // " << entry->meta << "\n"; out << prefix << " // " << entry->meta << "\n";
if(!entry->flags.empty())
out << prefix << " // flags: " << boost::algorithm::join(entry->flags, ", ") << "\n";
out << prefix; out << prefix;
} }
writeNode(*entry); writeNode(*entry);
@ -389,6 +393,18 @@ bool JsonParser::extractStruct(JsonNode &node)
if (!extractString(key)) if (!extractString(key))
return false; 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()) if (node.Struct().find(key) != node.Struct().end())
error("Dublicated element encountered!", true); error("Dublicated element encountered!", true);
@ -398,6 +414,10 @@ bool JsonParser::extractStruct(JsonNode &node)
if (!extractElement(node.Struct()[key], '}')) if (!extractElement(node.Struct()[key], '}'))
return false; 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] == '}') if (input[pos] == '}')
{ {
pos++; pos++;

View File

@ -70,7 +70,8 @@ JsonNode::JsonNode(ResourceID && fileURI, bool &isValidSyntax):
JsonNode::JsonNode(const JsonNode &copy): JsonNode::JsonNode(const JsonNode &copy):
type(JsonType::DATA_NULL), type(JsonType::DATA_NULL),
meta(copy.meta) meta(copy.meta),
flags(copy.flags)
{ {
setType(copy.getType()); setType(copy.getType());
switch(type) switch(type)
@ -96,6 +97,7 @@ void JsonNode::swap(JsonNode &b)
swap(meta, b.meta); swap(meta, b.meta);
swap(data, b.data); swap(data, b.data);
swap(type, b.type); swap(type, b.type);
swap(flags, b.flags);
} }
JsonNode & JsonNode::operator =(JsonNode node) JsonNode & JsonNode::operator =(JsonNode node)
@ -846,7 +848,7 @@ const JsonNode & JsonUtils::getSchema(std::string URI)
return getSchemaByName(filename).resolvePointer(URI.substr(posHash + 1)); 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) if (dest.getType() == JsonNode::JsonType::DATA_NULL)
{ {
@ -871,24 +873,31 @@ void JsonUtils::merge(JsonNode & dest, JsonNode & source)
break; break;
} }
case JsonNode::JsonType::DATA_STRUCT: case JsonNode::JsonType::DATA_STRUCT:
{
if(!noOverride && vstd::contains(source.flags, "override"))
{
std::swap(dest, source);
}
else
{ {
//recursively merge all entries from struct //recursively merge all entries from struct
for(auto & node : source.Struct()) for(auto & node : source.Struct())
merge(dest[node.first], node.second); 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 // 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) void JsonUtils::inherit(JsonNode & descendant, const JsonNode & base)
{ {
JsonNode inheritedNode(base); JsonNode inheritedNode(base);
merge(inheritedNode,descendant); merge(inheritedNode, descendant, true);
descendant.swap(inheritedNode); descendant.swap(inheritedNode);
} }

View File

@ -45,8 +45,10 @@ private:
JsonData data; JsonData data;
public: public:
/// free to use metadata field /// free to use metadata fields
std::string meta; std::string meta;
// meta-flags like override
std::vector<std::string> flags;
//Create empty node //Create empty node
JsonNode(JsonType Type = JsonType::DATA_NULL); JsonNode(JsonType Type = JsonType::DATA_NULL);
@ -119,6 +121,10 @@ public:
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & meta; h & meta;
if(version >= 782)
{
h & flags;
}
h & type; h & type;
switch(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 * 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 * @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 * @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 * 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 * @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 /** @brief recursively merges descendant into copy of base node
* Result emulates inheritance semantic * Result emulates inheritance semantic

View File

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