From 922966dcf884172ba2189603d41a53c01ee39117 Mon Sep 17 00:00:00 2001
From: Ivan Savenko <saven.ivan@gmail.com>
Date: Tue, 13 Feb 2024 14:34:16 +0200
Subject: [PATCH] Renamed JsonNode::meta to more logical modScope. Member is
 now private

---
 client/ClientCommandManager.cpp               |  2 +-
 lib/CArtHandler.cpp                           |  4 +--
 lib/CCreatureHandler.cpp                      |  6 ++--
 lib/CHeroHandler.cpp                          |  6 ++--
 lib/CTownHandler.cpp                          | 30 +++++++++----------
 lib/bonuses/BonusParams.cpp                   |  2 +-
 lib/json/JsonBonus.cpp                        |  4 +--
 lib/json/JsonNode.cpp                         | 13 +++++---
 lib/json/JsonNode.h                           |  9 +++---
 lib/json/JsonRandom.cpp                       |  4 +--
 lib/json/JsonUtils.cpp                        |  2 +-
 lib/json/JsonValidator.cpp                    | 20 ++++++-------
 lib/json/JsonWriter.cpp                       |  8 ++---
 .../CBankInstanceConstructor.cpp              |  2 +-
 .../CObjectClassesHandler.cpp                 | 10 +++----
 .../CRewardableConstructor.cpp                |  2 +-
 .../CommonConstructors.cpp                    |  2 +-
 .../DwellingInstanceConstructor.cpp           |  2 +-
 lib/mapping/CMapService.cpp                   |  2 +-
 lib/mapping/MapFormatH3M.cpp                  | 10 +++----
 lib/mapping/MapIdentifiersH3M.cpp             | 10 +++----
 lib/modding/CModInfo.cpp                      |  2 +-
 lib/modding/ContentTypeHandler.cpp            | 10 +++----
 lib/modding/IdentifierStorage.cpp             | 10 +++----
 lib/rewardable/Info.cpp                       |  6 ++--
 lib/serializer/JsonDeserializer.cpp           |  2 +-
 lib/spells/CSpellHandler.cpp                  |  4 +--
 lib/spells/TargetCondition.cpp                |  2 +-
 scripting/lua/LuaScriptingContext.cpp         |  4 +--
 scripting/lua/LuaSpellEffect.cpp              | 12 ++++----
 scripting/lua/LuaStack.cpp                    |  4 +--
 test/entity/CCreatureTest.cpp                 |  6 ++--
 test/game/CGameStateTest.cpp                  |  2 +-
 test/map/CMapFormatTest.cpp                   |  2 +-
 test/scripting/LuaSpellEffectAPITest.cpp      | 22 +++++++-------
 test/scripting/LuaSpellEffectTest.cpp         | 18 +++++------
 test/scripting/ScriptFixture.cpp              |  2 +-
 test/spells/TargetConditionTest.cpp           |  2 +-
 test/spells/effects/CatapultTest.cpp          |  2 +-
 test/spells/effects/CloneTest.cpp             |  2 +-
 test/spells/effects/DamageTest.cpp            |  4 +--
 test/spells/effects/DispelTest.cpp            |  6 ++--
 test/spells/effects/HealTest.cpp              | 16 +++++-----
 test/spells/effects/SacrificeTest.cpp         |  4 +--
 test/spells/effects/SummonTest.cpp            |  4 +--
 test/spells/effects/TimedTest.cpp             |  4 +--
 46 files changed, 154 insertions(+), 148 deletions(-)

diff --git a/client/ClientCommandManager.cpp b/client/ClientCommandManager.cpp
index 09ea67004..cf02eead0 100644
--- a/client/ClientCommandManager.cpp
+++ b/client/ClientCommandManager.cpp
@@ -248,7 +248,7 @@ void ClientCommandManager::handleGetConfigCommand()
 			{
 				const JsonNode& object = nameAndObject.second;
 
-				std::string name = ModUtility::makeFullIdentifier(object.meta, contentName, nameAndObject.first);
+				std::string name = ModUtility::makeFullIdentifier(object.getModScope(), contentName, nameAndObject.first);
 
 				boost::algorithm::replace_all(name, ":", "_");
 
diff --git a/lib/CArtHandler.cpp b/lib/CArtHandler.cpp
index 6a205217a..f5bac24e5 100644
--- a/lib/CArtHandler.cpp
+++ b/lib/CArtHandler.cpp
@@ -461,7 +461,7 @@ CArtifact * CArtHandler::loadFromJson(const std::string & scope, const JsonNode
 	VLC->identifiers()->requestIdentifier(scope, "object", "artifact", [=](si32 index)
 	{
 		JsonNode conf;
-		conf.setMeta(scope);
+		conf.setModScope(scope);
 
 		VLC->objtypeh->loadSubObject(art->identifier, conf, Obj::ARTIFACT, art->getIndex());
 
@@ -469,7 +469,7 @@ CArtifact * CArtHandler::loadFromJson(const std::string & scope, const JsonNode
 		{
 			JsonNode templ;
 			templ["animation"].String() = art->advMapDef;
-			templ.setMeta(scope);
+			templ.setModScope(scope);
 
 			// add new template.
 			// Necessary for objects added via mods that don't have any templates in H3
diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp
index 36db9c134..21fda1133 100644
--- a/lib/CCreatureHandler.cpp
+++ b/lib/CCreatureHandler.cpp
@@ -418,7 +418,7 @@ void CCreatureHandler::loadCommanders()
 
 	std::string modSource = VLC->modh->findResourceOrigin(configResource);
 	JsonNode data(configResource);
-	data.setMeta(modSource);
+	data.setModScope(modSource);
 
 	const JsonNode & config = data; // switch to const data accessors
 
@@ -640,7 +640,7 @@ CCreature * CCreatureHandler::loadFromJson(const std::string & scope, const Json
 	VLC->identifiers()->requestIdentifier(scope, "object", "monster", [=](si32 index)
 	{
 		JsonNode conf;
-		conf.setMeta(scope);
+		conf.setModScope(scope);
 
 		VLC->objtypeh->loadSubObject(cre->identifier, conf, Obj::MONSTER, cre->getId().num);
 		if (!advMapFile.isNull())
@@ -649,7 +649,7 @@ CCreature * CCreatureHandler::loadFromJson(const std::string & scope, const Json
 			templ["animation"] = advMapFile;
 			if (!advMapMask.isNull())
 				templ["mask"] = advMapMask;
-			templ.setMeta(scope);
+			templ.setModScope(scope);
 
 			// if creature has custom advMapFile, reset any potentially imported H3M templates and use provided file instead
 			VLC->objtypeh->getHandlerFor(Obj::MONSTER, cre->getId().num)->clearTemplates();
diff --git a/lib/CHeroHandler.cpp b/lib/CHeroHandler.cpp
index 5f96c9999..e73f9bd0b 100644
--- a/lib/CHeroHandler.cpp
+++ b/lib/CHeroHandler.cpp
@@ -293,7 +293,7 @@ CHeroClass * CHeroClassHandler::loadFromJson(const std::string & scope, const Js
 	for(auto skillPair : node["secondarySkills"].Struct())
 	{
 		int probability = static_cast<int>(skillPair.second.Integer());
-		VLC->identifiers()->requestIdentifier(skillPair.second.meta, "skill", skillPair.first, [heroClass, probability](si32 skillID)
+		VLC->identifiers()->requestIdentifier(skillPair.second.getModScope(), "skill", skillPair.first, [heroClass, probability](si32 skillID)
 		{
 			heroClass->secSkillProbability[skillID] = probability;
 		});
@@ -310,7 +310,7 @@ CHeroClass * CHeroClassHandler::loadFromJson(const std::string & scope, const Js
 	{
 		int value = static_cast<int>(tavern.second.Float());
 
-		VLC->identifiers()->requestIdentifier(tavern.second.meta, "faction", tavern.first,
+		VLC->identifiers()->requestIdentifier(tavern.second.getModScope(), "faction", tavern.first,
 		[=](si32 factionID)
 		{
 			heroClass->selectionProbability[FactionID(factionID)] = value;
@@ -329,7 +329,7 @@ CHeroClass * CHeroClassHandler::loadFromJson(const std::string & scope, const Js
 		classConf["heroClass"].String() = identifier;
 		if (!node["compatibilityIdentifiers"].isNull())
 			classConf["compatibilityIdentifiers"] = node["compatibilityIdentifiers"];
-		classConf.setMeta(scope);
+		classConf.setModScope(scope);
 		VLC->objtypeh->loadSubObject(identifier, classConf, index, heroClass->getIndex());
 	});
 
diff --git a/lib/CTownHandler.cpp b/lib/CTownHandler.cpp
index 40be76616..5eb5b2e4b 100644
--- a/lib/CTownHandler.cpp
+++ b/lib/CTownHandler.cpp
@@ -617,7 +617,7 @@ void CTownHandler::loadSpecialBuildingBonuses(const JsonNode & source, BonusList
 void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, const JsonNode & source)
 {
 	assert(stringID.find(':') == std::string::npos);
-	assert(!source.meta.empty());
+	assert(!source.getModScope().empty());
 
 	auto * ret = new CBuilding();
 	ret->bid = getMappedValue<BuildingID, std::string>(stringID, BuildingID::NONE, MappedKeys::BUILDING_NAMES_TO_TYPES, false);
@@ -640,11 +640,11 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons
 	ret->height = getMappedValue<CBuilding::ETowerHeight>(source["height"], CBuilding::HEIGHT_NO_TOWER, CBuilding::TOWER_TYPES);
 
 	ret->identifier = stringID;
-	ret->modScope = source.meta;
+	ret->modScope = source.getModScope();
 	ret->town = town;
 
-	VLC->generaltexth->registerString(source.meta, ret->getNameTextID(), source["name"].String());
-	VLC->generaltexth->registerString(source.meta, ret->getDescriptionTextID(), source["description"].String());
+	VLC->generaltexth->registerString(source.getModScope(), ret->getNameTextID(), source["name"].String());
+	VLC->generaltexth->registerString(source.getModScope(), ret->getDescriptionTextID(), source["description"].String());
 
 	ret->resources = TResources(source["cost"]);
 	ret->produce =   TResources(source["produce"]);
@@ -729,7 +729,7 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons
 
 	ret->town->buildings[ret->bid] = ret;
 
-	registerObject(source.meta, ret->town->getBuildingScope(), ret->identifier, ret->bid.getNum());
+	registerObject(source.getModScope(), ret->town->getBuildingScope(), ret->identifier, ret->bid.getNum());
 }
 
 void CTownHandler::loadBuildings(CTown * town, const JsonNode & source)
@@ -751,14 +751,14 @@ void CTownHandler::loadStructure(CTown &town, const std::string & stringID, cons
 	ret->building = nullptr;
 	ret->buildable = nullptr;
 
-	VLC->identifiers()->tryRequestIdentifier( source.meta, "building." + town.faction->getJsonKey(), stringID, [=, &town](si32 identifier) mutable
+	VLC->identifiers()->tryRequestIdentifier( source.getModScope(), "building." + town.faction->getJsonKey(), stringID, [=, &town](si32 identifier) mutable
 	{
 		ret->building = town.buildings[BuildingID(identifier)];
 	});
 
 	if (source["builds"].isNull())
 	{
-		VLC->identifiers()->tryRequestIdentifier( source.meta, "building." + town.faction->getJsonKey(), stringID, [=, &town](si32 identifier) mutable
+		VLC->identifiers()->tryRequestIdentifier( source.getModScope(), "building." + town.faction->getJsonKey(), stringID, [=, &town](si32 identifier) mutable
 		{
 			ret->building = town.buildings[BuildingID(identifier)];
 		});
@@ -944,7 +944,7 @@ void CTownHandler::loadTown(CTown * town, const JsonNode & source)
 	}
 	else
 	{
-		VLC->identifiers()->requestIdentifier( source.meta, "spell", "castleMoat", [=](si32 ability)
+		VLC->identifiers()->requestIdentifier( source.getModScope(), "spell", "castleMoat", [=](si32 ability)
 		{
 			town->moatAbility = SpellID(ability);
 		});
@@ -984,7 +984,7 @@ void CTownHandler::loadTown(CTown * town, const JsonNode & source)
 	{
 		int chance = static_cast<int>(node.second.Float());
 
-		VLC->identifiers()->requestIdentifier(node.second.meta, "heroClass",node.first, [=](si32 classID)
+		VLC->identifiers()->requestIdentifier(node.second.getModScope(), "heroClass",node.first, [=](si32 classID)
 		{
 			VLC->heroclassesh->objects[classID]->selectionProbability[town->faction->getId()] = chance;
 		});
@@ -994,7 +994,7 @@ void CTownHandler::loadTown(CTown * town, const JsonNode & source)
 	{
 		int chance = static_cast<int>(node.second.Float());
 
-		VLC->identifiers()->requestIdentifier(node.second.meta, "spell", node.first, [=](si32 spellID)
+		VLC->identifiers()->requestIdentifier(node.second.getModScope(), "spell", node.first, [=](si32 spellID)
 		{
 			VLC->spellh->objects.at(spellID)->probabilities[town->faction->getId()] = chance;
 		});
@@ -1120,9 +1120,9 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod
 			// register town once objects are loaded
 			JsonNode config = data["town"]["mapObject"];
 			config["faction"].String() = name;
-			config["faction"].meta = scope;
-			if (config.meta.empty())// MODS COMPATIBILITY FOR 0.96
-				config.meta = scope;
+			config["faction"].setModScope(scope, false);
+			if (config.getModScope().empty())// MODS COMPATIBILITY FOR 0.96
+				config.setModScope(scope, false);
 			VLC->objtypeh->loadSubObject(object->identifier, config, index, object->index);
 
 			// MODS COMPATIBILITY FOR 0.96
@@ -1163,7 +1163,7 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod
 			// register town once objects are loaded
 			JsonNode config = data["town"]["mapObject"];
 			config["faction"].String() = name;
-			config["faction"].meta = scope;
+			config["faction"].setModScope(scope, false);
 			VLC->objtypeh->loadSubObject(object->identifier, config, index, object->index);
 		});
 	}
@@ -1174,7 +1174,7 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod
 void CTownHandler::loadRandomFaction()
 {
 	JsonNode randomFactionJson(JsonPath::builtin("config/factions/random.json"));
-	randomFactionJson.setMeta(ModScope::scopeBuiltin(), true);
+	randomFactionJson.setModScope(ModScope::scopeBuiltin(), true);
 	loadBuildings(randomTown, randomFactionJson["random"]["town"]["buildings"]);
 }
 
diff --git a/lib/bonuses/BonusParams.cpp b/lib/bonuses/BonusParams.cpp
index 7274c0d9e..5b2765678 100644
--- a/lib/bonuses/BonusParams.cpp
+++ b/lib/bonuses/BonusParams.cpp
@@ -353,7 +353,7 @@ const JsonNode & BonusParams::toJson()
 			ret["targetSourceType"].String() = vstd::findKey(bonusSourceMap, *targetType);
 		jsonCreated = true;
 	}
-	ret.setMeta(ModScope::scopeGame());
+	ret.setModScope(ModScope::scopeGame());
 	return ret;
 };
 
diff --git a/lib/json/JsonBonus.cpp b/lib/json/JsonBonus.cpp
index 75437c8bb..5288560b0 100644
--- a/lib/json/JsonBonus.cpp
+++ b/lib/json/JsonBonus.cpp
@@ -40,14 +40,14 @@ static void loadBonusSubtype(BonusSubtypeID & subtype, BonusType type, const Jso
 
 	if (node.isNumber()) // Compatibility code for 1.3 or older
 	{
-		logMod->warn("Bonus subtype must be string! (%s)", node.meta);
+		logMod->warn("Bonus subtype must be string! (%s)", node.getModScope());
 		subtype = BonusCustomSubtype(node.Integer());
 		return;
 	}
 
 	if (!node.isString())
 	{
-		logMod->warn("Bonus subtype must be string! (%s)", node.meta);
+		logMod->warn("Bonus subtype must be string! (%s)", node.getModScope());
 		subtype = BonusSubtypeID();
 		return;
 	}
diff --git a/lib/json/JsonNode.cpp b/lib/json/JsonNode.cpp
index 290e3a647..bd41d2549 100644
--- a/lib/json/JsonNode.cpp
+++ b/lib/json/JsonNode.cpp
@@ -124,9 +124,14 @@ JsonNode::JsonType JsonNode::getType() const
 	return static_cast<JsonType>(data.index());
 }
 
-void JsonNode::setMeta(const std::string & metadata, bool recursive)
+const std::string & JsonNode::getModScope() const
 {
-	meta = metadata;
+	return modScope;
+}
+
+void JsonNode::setModScope(const std::string & metadata, bool recursive)
+{
+	modScope = metadata;
 	if (recursive)
 	{
 		switch (getType())
@@ -135,14 +140,14 @@ void JsonNode::setMeta(const std::string & metadata, bool recursive)
 			{
 				for(auto & node : Vector())
 				{
-					node.setMeta(metadata);
+					node.setModScope(metadata);
 				}
 			}
 			break; case JsonType::DATA_STRUCT:
 			{
 				for(auto & node : Struct())
 				{
-					node.second.setMeta(metadata);
+					node.second.setModScope(metadata);
 				}
 			}
 		}
diff --git a/lib/json/JsonNode.h b/lib/json/JsonNode.h
index 14374c09d..3962316c0 100644
--- a/lib/json/JsonNode.h
+++ b/lib/json/JsonNode.h
@@ -41,9 +41,9 @@ private:
 
 	JsonData data;
 
+	/// Mod-origin of this particular field
+	std::string modScope;
 public:
-	/// free to use metadata fields
-	std::string meta;
 	/// meta-flags like override
 	std::vector<std::string> flags;
 
@@ -68,7 +68,8 @@ public:
 	bool operator == (const JsonNode &other) const;
 	bool operator != (const JsonNode &other) const;
 
-	void setMeta(const std::string & metadata, bool recursive = true);
+	const std::string & getModScope() const;
+	void setModScope(const std::string & metadata, bool recursive = true);
 
 	/// Convert node to another type. Converting to nullptr will clear all data
 	void setType(JsonType Type);
@@ -130,7 +131,7 @@ public:
 
 	template <typename Handler> void serialize(Handler &h)
 	{
-		h & meta;
+		h & modScope;
 		h & flags;
 		h & data;
 	}
diff --git a/lib/json/JsonRandom.cpp b/lib/json/JsonRandom.cpp
index 9490ce244..1c5234ac8 100644
--- a/lib/json/JsonRandom.cpp
+++ b/lib/json/JsonRandom.cpp
@@ -321,7 +321,7 @@ VCMI_LIB_NAMESPACE_BEGIN
 		{
 			for(const auto & pair : value.Struct())
 			{
-				PrimarySkill id = decodeKey<PrimarySkill>(pair.second.meta, pair.first, variables);
+				PrimarySkill id = decodeKey<PrimarySkill>(pair.second.getModScope(), pair.first, variables);
 				ret[id.getNum()] += loadValue(pair.second, rng, variables);
 			}
 		}
@@ -357,7 +357,7 @@ VCMI_LIB_NAMESPACE_BEGIN
 		{
 			for(const auto & pair : value.Struct())
 			{
-				SecondarySkill id = decodeKey<SecondarySkill>(pair.second.meta, pair.first, variables);
+				SecondarySkill id = decodeKey<SecondarySkill>(pair.second.getModScope(), pair.first, variables);
 				ret[id] = loadValue(pair.second, rng, variables);
 			}
 		}
diff --git a/lib/json/JsonUtils.cpp b/lib/json/JsonUtils.cpp
index 643ef1488..1c9b2be20 100644
--- a/lib/json/JsonUtils.cpp
+++ b/lib/json/JsonUtils.cpp
@@ -230,7 +230,7 @@ void JsonUtils::merge(JsonNode & dest, JsonNode & source, bool ignoreOverride, b
 			else
 			{
 				if (copyMeta)
-					dest.meta = source.meta;
+					dest.setModScope(source.getModScope(), false);
 
 				//recursively merge all entries from struct
 				for(auto & node : source.Struct())
diff --git a/lib/json/JsonValidator.cpp b/lib/json/JsonValidator.cpp
index a894282e8..b4090af82 100644
--- a/lib/json/JsonValidator.cpp
+++ b/lib/json/JsonValidator.cpp
@@ -469,45 +469,45 @@ namespace
 
 		std::string textFile(const JsonNode & node)
 		{
-			TEST_FILE(node.meta, "", node.String(), EResType::JSON);
+			TEST_FILE(node.getModScope(), "", node.String(), EResType::JSON);
 			return "Text file \"" + node.String() + "\" was not found";
 		}
 
 		std::string musicFile(const JsonNode & node)
 		{
-			TEST_FILE(node.meta, "Music/", node.String(), EResType::SOUND);
-			TEST_FILE(node.meta, "", node.String(), EResType::SOUND);
+			TEST_FILE(node.getModScope(), "Music/", node.String(), EResType::SOUND);
+			TEST_FILE(node.getModScope(), "", node.String(), EResType::SOUND);
 			return "Music file \"" + node.String() + "\" was not found";
 		}
 
 		std::string soundFile(const JsonNode & node)
 		{
-			TEST_FILE(node.meta, "Sounds/", node.String(), EResType::SOUND);
+			TEST_FILE(node.getModScope(), "Sounds/", node.String(), EResType::SOUND);
 			return "Sound file \"" + node.String() + "\" was not found";
 		}
 
 		std::string defFile(const JsonNode & node)
 		{
-			return testAnimation(node.String(), node.meta);
+			return testAnimation(node.String(), node.getModScope());
 		}
 
 		std::string animationFile(const JsonNode & node)
 		{
-			return testAnimation(node.String(), node.meta);
+			return testAnimation(node.String(), node.getModScope());
 		}
 
 		std::string imageFile(const JsonNode & node)
 		{
-			TEST_FILE(node.meta, "Data/", node.String(), EResType::IMAGE);
-			TEST_FILE(node.meta, "Sprites/", node.String(), EResType::IMAGE);
+			TEST_FILE(node.getModScope(), "Data/", node.String(), EResType::IMAGE);
+			TEST_FILE(node.getModScope(), "Sprites/", node.String(), EResType::IMAGE);
 			if (node.String().find(':') != std::string::npos)
-				return testAnimation(node.String().substr(0, node.String().find(':')), node.meta);
+				return testAnimation(node.String().substr(0, node.String().find(':')), node.getModScope());
 			return "Image file \"" + node.String() + "\" was not found";
 		}
 
 		std::string videoFile(const JsonNode & node)
 		{
-			TEST_FILE(node.meta, "Video/", node.String(), EResType::VIDEO);
+			TEST_FILE(node.getModScope(), "Video/", node.String(), EResType::VIDEO);
 			return "Video file \"" + node.String() + "\" was not found";
 		}
 
diff --git a/lib/json/JsonWriter.cpp b/lib/json/JsonWriter.cpp
index 2a4092b65..f777a18b4 100644
--- a/lib/json/JsonWriter.cpp
+++ b/lib/json/JsonWriter.cpp
@@ -37,8 +37,8 @@ void JsonWriter::writeEntry(JsonMap::const_iterator entry)
 {
 	if(!compactMode)
 	{
-		if (!entry->second.meta.empty())
-			out << prefix << " // " << entry->second.meta << "\n";
+		if (!entry->second.getModScope().empty())
+			out << prefix << " // " << entry->second.getModScope() << "\n";
 		if(!entry->second.flags.empty())
 			out << prefix << " // flags: " << boost::algorithm::join(entry->second.flags, ", ") << "\n";
 		out << prefix;
@@ -52,8 +52,8 @@ void JsonWriter::writeEntry(JsonVector::const_iterator entry)
 {
 	if(!compactMode)
 	{
-		if (!entry->meta.empty())
-			out << prefix << " // " << entry->meta << "\n";
+		if (!entry->getModScope().empty())
+			out << prefix << " // " << entry->getModScope() << "\n";
 		if(!entry->flags.empty())
 			out << prefix << " // flags: " << boost::algorithm::join(entry->flags, ", ") << "\n";
 		out << prefix;
diff --git a/lib/mapObjectConstructors/CBankInstanceConstructor.cpp b/lib/mapObjectConstructors/CBankInstanceConstructor.cpp
index 170aa1239..00c800173 100644
--- a/lib/mapObjectConstructors/CBankInstanceConstructor.cpp
+++ b/lib/mapObjectConstructors/CBankInstanceConstructor.cpp
@@ -27,7 +27,7 @@ void CBankInstanceConstructor::initTypeData(const JsonNode & input)
 	if (input.Struct().count("name") == 0)
 		logMod->warn("Bank %s missing name!", getJsonKey());
 
-	VLC->generaltexth->registerString(input.meta, getNameTextID(), input["name"].String());
+	VLC->generaltexth->registerString(input.getModScope(), getNameTextID(), input["name"].String());
 
 	levels = input["levels"].Vector();
 	bankResetDuration = static_cast<si32>(input["resetDuration"].Float());
diff --git a/lib/mapObjectConstructors/CObjectClassesHandler.cpp b/lib/mapObjectConstructors/CObjectClassesHandler.cpp
index e6ee4f2dd..147590e2b 100644
--- a/lib/mapObjectConstructors/CObjectClassesHandler.cpp
+++ b/lib/mapObjectConstructors/CObjectClassesHandler.cpp
@@ -259,21 +259,21 @@ std::unique_ptr<ObjectClass> CObjectClassesHandler::loadFromJson(const std::stri
 	{
 		if (!subData.second["index"].isNull())
 		{
-			const std::string & subMeta = subData.second["index"].meta;
+			const std::string & subMeta = subData.second["index"].getModScope();
 
 			if ( subMeta == "core")
 			{
 				size_t subIndex = subData.second["index"].Integer();
-				loadSubObject(subData.second.meta, subData.first, subData.second, obj.get(), subIndex);
+				loadSubObject(subData.second.getModScope(), subData.first, subData.second, obj.get(), subIndex);
 			}
 			else
 			{
 				logMod->error("Object %s:%s.%s - attempt to load object with preset index! This option is reserved for built-in mod", subMeta, name, subData.first );
-				loadSubObject(subData.second.meta, subData.first, subData.second, obj.get());
+				loadSubObject(subData.second.getModScope(), subData.first, subData.second, obj.get());
 			}
 		}
 		else
-			loadSubObject(subData.second.meta, subData.first, subData.second, obj.get());
+			loadSubObject(subData.second.getModScope(), subData.first, subData.second, obj.get());
 	}
 
 	if (obj->id == MapObjectID::MONOLITH_TWO_WAY)
@@ -306,7 +306,7 @@ void CObjectClassesHandler::loadSubObject(const std::string & identifier, JsonNo
 		objects.at(ID.getNum())->objects.resize(subID.getNum()+1);
 
 	JsonUtils::inherit(config, objects.at(ID.getNum())->base);
-	loadSubObject(config.meta, identifier, config, objects.at(ID.getNum()).get(), subID.getNum());
+	loadSubObject(config.getModScope(), identifier, config, objects.at(ID.getNum()).get(), subID.getNum());
 }
 
 void CObjectClassesHandler::removeSubObject(MapObjectID ID, MapObjectSubID subID)
diff --git a/lib/mapObjectConstructors/CRewardableConstructor.cpp b/lib/mapObjectConstructors/CRewardableConstructor.cpp
index 83242529b..72d61e796 100644
--- a/lib/mapObjectConstructors/CRewardableConstructor.cpp
+++ b/lib/mapObjectConstructors/CRewardableConstructor.cpp
@@ -22,7 +22,7 @@ void CRewardableConstructor::initTypeData(const JsonNode & config)
 	blockVisit = config["blockedVisitable"].Bool();
 
 	if (!config["name"].isNull())
-		VLC->generaltexth->registerString( config.meta, getNameTextID(), config["name"].String());
+		VLC->generaltexth->registerString( config.getModScope(), getNameTextID(), config["name"].String());
 	
 }
 
diff --git a/lib/mapObjectConstructors/CommonConstructors.cpp b/lib/mapObjectConstructors/CommonConstructors.cpp
index 41ea8f9fc..806b32194 100644
--- a/lib/mapObjectConstructors/CommonConstructors.cpp
+++ b/lib/mapObjectConstructors/CommonConstructors.cpp
@@ -67,7 +67,7 @@ void CTownInstanceConstructor::initTypeData(const JsonNode & input)
 
 	// change scope of "filters" to scope of object that is being loaded
 	// since this filters require to resolve building ID's
-	filtersJson.setMeta(input["faction"].meta);
+	filtersJson.setModScope(input["faction"].getModScope());
 }
 
 void CTownInstanceConstructor::afterLoadFinalization()
diff --git a/lib/mapObjectConstructors/DwellingInstanceConstructor.cpp b/lib/mapObjectConstructors/DwellingInstanceConstructor.cpp
index c52281505..83f20becf 100644
--- a/lib/mapObjectConstructors/DwellingInstanceConstructor.cpp
+++ b/lib/mapObjectConstructors/DwellingInstanceConstructor.cpp
@@ -29,7 +29,7 @@ void DwellingInstanceConstructor::initTypeData(const JsonNode & input)
 	if (input.Struct().count("name") == 0)
 		logMod->warn("Dwelling %s missing name!", getJsonKey());
 
-	VLC->generaltexth->registerString( input.meta, getNameTextID(), input["name"].String());
+	VLC->generaltexth->registerString( input.getModScope(), getNameTextID(), input["name"].String());
 
 	const JsonVector & levels = input["creatures"].Vector();
 	const auto totalLevels = levels.size();
diff --git a/lib/mapping/CMapService.cpp b/lib/mapping/CMapService.cpp
index f78a67ee5..cf70f7b08 100644
--- a/lib/mapping/CMapService.cpp
+++ b/lib/mapping/CMapService.cpp
@@ -171,7 +171,7 @@ static JsonNode loadPatches(const std::string & path)
 	for (auto & entry : node.Struct())
 		JsonUtils::validate(entry.second, "vcmi:mapHeader", "patch for " + entry.first);
 
-	node.setMeta(ModScope::scopeMap());
+	node.setModScope(ModScope::scopeMap());
 	return node;
 }
 
diff --git a/lib/mapping/MapFormatH3M.cpp b/lib/mapping/MapFormatH3M.cpp
index c9a2a9b40..3f3c64606 100644
--- a/lib/mapping/MapFormatH3M.cpp
+++ b/lib/mapping/MapFormatH3M.cpp
@@ -1153,7 +1153,7 @@ CGObjectInstance * CMapLoaderH3M::readWitchHut(const int3 & position, std::share
 				variable["anyOf"].Vector() = anyOfList;
 			}
 
-			variable.setMeta(ModScope::scopeGame()); // list may include skills from all mods
+			variable.setModScope(ModScope::scopeGame()); // list may include skills from all mods
 			rewardable->configuration.presetVariable("secondarySkill", "gainedSkill", variable);
 		}
 		else
@@ -1189,7 +1189,7 @@ CGObjectInstance * CMapLoaderH3M::readScholar(const int3 & position, std::shared
 				JsonNode variable;
 				JsonNode dice;
 				variable.String() = NPrimarySkill::names[bonusID];
-				variable.setMeta(ModScope::scopeGame());
+				variable.setModScope(ModScope::scopeGame());
 				dice.Integer() = 80;
 				rewardable->configuration.presetVariable("primarySkill", "gainedStat", variable);
 				rewardable->configuration.presetVariable("dice", "0", dice);
@@ -1200,7 +1200,7 @@ CGObjectInstance * CMapLoaderH3M::readScholar(const int3 & position, std::shared
 				JsonNode variable;
 				JsonNode dice;
 				variable.String() = VLC->skills()->getByIndex(bonusID)->getJsonKey();
-				variable.setMeta(ModScope::scopeGame());
+				variable.setModScope(ModScope::scopeGame());
 				dice.Integer() = 50;
 				rewardable->configuration.presetVariable("secondarySkill", "gainedSkill", variable);
 				rewardable->configuration.presetVariable("dice", "0", dice);
@@ -1211,7 +1211,7 @@ CGObjectInstance * CMapLoaderH3M::readScholar(const int3 & position, std::shared
 				JsonNode variable;
 				JsonNode dice;
 				variable.String() = VLC->spells()->getByIndex(bonusID)->getJsonKey();
-				variable.setMeta(ModScope::scopeGame());
+				variable.setModScope(ModScope::scopeGame());
 				dice.Integer() = 20;
 				rewardable->configuration.presetVariable("spell", "gainedSpell", variable);
 				rewardable->configuration.presetVariable("dice", "0", dice);
@@ -1356,7 +1356,7 @@ CGObjectInstance * CMapLoaderH3M::readShrine(const int3 & position, std::shared_
 		{
 			JsonNode variable;
 			variable.String() = VLC->spells()->getById(spell)->getJsonKey();
-			variable.setMeta(ModScope::scopeGame()); // list may include spells from all mods
+			variable.setModScope(ModScope::scopeGame()); // list may include spells from all mods
 			rewardable->configuration.presetVariable("spell", "gainedSpell", variable);
 		}
 	}
diff --git a/lib/mapping/MapIdentifiersH3M.cpp b/lib/mapping/MapIdentifiersH3M.cpp
index 15a7602ce..f51334a2a 100644
--- a/lib/mapping/MapIdentifiersH3M.cpp
+++ b/lib/mapping/MapIdentifiersH3M.cpp
@@ -28,7 +28,7 @@ void MapIdentifiersH3M::loadMapping(std::map<IdentifierID, IdentifierID> & resul
 	for (auto entry : mapping.Struct())
 	{
 		IdentifierID sourceID (entry.second.Integer());
-		IdentifierID targetID (*VLC->identifiers()->getIdentifier(entry.second.meta, identifierName, entry.first));
+		IdentifierID targetID (*VLC->identifiers()->getIdentifier(entry.second.getModScope(), identifierName, entry.first));
 
 		result[sourceID] = targetID;
 	}
@@ -41,13 +41,13 @@ void MapIdentifiersH3M::loadMapping(const JsonNode & mapping)
 
 	for (auto entryFaction : mapping["buildings"].Struct())
 	{
-		FactionID factionID (*VLC->identifiers()->getIdentifier(entryFaction.second.meta, "faction", entryFaction.first));
+		FactionID factionID (*VLC->identifiers()->getIdentifier(entryFaction.second.getModScope(), "faction", entryFaction.first));
 		auto buildingMap = entryFaction.second;
 
 		for (auto entryBuilding : buildingMap.Struct())
 		{
 			BuildingID sourceID (entryBuilding.second.Integer());
-			BuildingID targetID (*VLC->identifiers()->getIdentifier(entryBuilding.second.meta, "building." + VLC->factions()->getById(factionID)->getJsonKey(), entryBuilding.first));
+			BuildingID targetID (*VLC->identifiers()->getIdentifier(entryBuilding.second.getModScope(), "building." + VLC->factions()->getById(factionID)->getJsonKey(), entryBuilding.first));
 
 			mappingFactionBuilding[factionID][sourceID] = targetID;
 		}
@@ -70,7 +70,7 @@ void MapIdentifiersH3M::loadMapping(const JsonNode & mapping)
 		{
 			for (auto entryInner : entryOuter.second.Struct())
 			{
-				auto handler = VLC->objtypeh->getHandlerFor( entryInner.second.meta, entryOuter.first, entryInner.first);
+				auto handler = VLC->objtypeh->getHandlerFor( entryInner.second.getModScope(), entryOuter.first, entryInner.first);
 
 				auto entryValues = entryInner.second.Vector();
 				ObjectTypeIdentifier h3mID{Obj(entryValues[0].Integer()), int32_t(entryValues[1].Integer())};
@@ -80,7 +80,7 @@ void MapIdentifiersH3M::loadMapping(const JsonNode & mapping)
 		}
 		else
 		{
-			auto handler = VLC->objtypeh->getHandlerFor( entryOuter.second.meta, entryOuter.first, entryOuter.first);
+			auto handler = VLC->objtypeh->getHandlerFor( entryOuter.second.getModScope(), entryOuter.first, entryOuter.first);
 
 			auto entryValues = entryOuter.second.Vector();
 			ObjectTypeIdentifier h3mID{Obj(entryValues[0].Integer()), int32_t(entryValues[1].Integer())};
diff --git a/lib/modding/CModInfo.cpp b/lib/modding/CModInfo.cpp
index dab87979a..8690c17d0 100644
--- a/lib/modding/CModInfo.cpp
+++ b/lib/modding/CModInfo.cpp
@@ -18,7 +18,7 @@ VCMI_LIB_NAMESPACE_BEGIN
 
 static JsonNode addMeta(JsonNode config, const std::string & meta)
 {
-	config.setMeta(meta);
+	config.setModScope(meta);
 	return config;
 }
 
diff --git a/lib/modding/ContentTypeHandler.cpp b/lib/modding/ContentTypeHandler.cpp
index 0c2abf99a..5817188e8 100644
--- a/lib/modding/ContentTypeHandler.cpp
+++ b/lib/modding/ContentTypeHandler.cpp
@@ -45,7 +45,7 @@ ContentTypeHandler::ContentTypeHandler(IHandlerBase * handler, const std::string
 {
 	for(auto & node : originalData)
 	{
-		node.setMeta(ModScope::scopeBuiltin());
+		node.setModScope(ModScope::scopeBuiltin());
 	}
 }
 
@@ -53,7 +53,7 @@ bool ContentTypeHandler::preloadModData(const std::string & modName, const std::
 {
 	bool result = false;
 	JsonNode data = JsonUtils::assembleFromFiles(fileList, result);
-	data.setMeta(modName);
+	data.setModScope(modName);
 
 	ModInfo & modInfo = modData[modName];
 
@@ -104,7 +104,7 @@ bool ContentTypeHandler::loadMod(const std::string & modName, bool validate)
 		const std::string & name = entry.first;
 		JsonNode & data = entry.second;
 
-		if (data.meta != modName)
+		if (data.getModScope() != modName)
 		{
 			// in this scenario, entire object record comes from another mod
 			// normally, this is used to "patch" object from another mod (which is legal)
@@ -112,7 +112,7 @@ bool ContentTypeHandler::loadMod(const std::string & modName, bool validate)
 			// - another mod attempts to add object into this mod (technically can be supported, but might lead to weird edge cases)
 			// - another mod attempts to edit object from this mod that no longer exist - DANGER since such patch likely has very incomplete data
 			// so emit warning and skip such case
-			logMod->warn("Mod '%s' attempts to edit object '%s' of type '%s' from mod '%s' but no such object exist!", data.meta, name, objectName, modName);
+			logMod->warn("Mod '%s' attempts to edit object '%s' of type '%s' from mod '%s' but no such object exist!", data.getModScope(), name, objectName, modName);
 			continue;
 		}
 
@@ -163,7 +163,7 @@ void ContentTypeHandler::afterLoadFinalization()
 		if (data.second.modData.isNull())
 		{
 			for (auto node : data.second.patches.Struct())
-				logMod->warn("Mod '%s' have added patch for object '%s' from mod '%s', but this mod was not loaded or has no new objects.", node.second.meta, node.first, data.first);
+				logMod->warn("Mod '%s' have added patch for object '%s' from mod '%s', but this mod was not loaded or has no new objects.", node.second.getModScope(), node.first, data.first);
 		}
 
 		for(auto & otherMod : modData)
diff --git a/lib/modding/IdentifierStorage.cpp b/lib/modding/IdentifierStorage.cpp
index dd17b15ae..589a79f44 100644
--- a/lib/modding/IdentifierStorage.cpp
+++ b/lib/modding/IdentifierStorage.cpp
@@ -180,12 +180,12 @@ void CIdentifierStorage::requestIdentifier(const std::string & scope, const std:
 
 void CIdentifierStorage::requestIdentifier(const std::string & type, const JsonNode & name, const std::function<void(si32)> & callback) const
 {
-	requestIdentifier(ObjectCallback::fromNameAndType(name.meta, type, name.String(), callback, false));
+	requestIdentifier(ObjectCallback::fromNameAndType(name.getModScope(), type, name.String(), callback, false));
 }
 
 void CIdentifierStorage::requestIdentifier(const JsonNode & name, const std::function<void(si32)> & callback) const
 {
-	requestIdentifier(ObjectCallback::fromNameWithType(name.meta, name.String(), callback, false));
+	requestIdentifier(ObjectCallback::fromNameWithType(name.getModScope(), name.String(), callback, false));
 }
 
 void CIdentifierStorage::tryRequestIdentifier(const std::string & scope, const std::string & type, const std::string & name, const std::function<void(si32)> & callback) const
@@ -195,7 +195,7 @@ void CIdentifierStorage::tryRequestIdentifier(const std::string & scope, const s
 
 void CIdentifierStorage::tryRequestIdentifier(const std::string & type, const JsonNode & name, const std::function<void(si32)> & callback) const
 {
-	requestIdentifier(ObjectCallback::fromNameAndType(name.meta, type, name.String(), callback, true));
+	requestIdentifier(ObjectCallback::fromNameAndType(name.getModScope(), type, name.String(), callback, true));
 }
 
 std::optional<si32> CIdentifierStorage::getIdentifier(const std::string & scope, const std::string & type, const std::string & name, bool silent) const
@@ -210,7 +210,7 @@ std::optional<si32> CIdentifierStorage::getIdentifier(const std::string & type,
 {
 	assert(state != ELoadingState::LOADING);
 
-	auto options = ObjectCallback::fromNameAndType(name.meta, type, name.String(), std::function<void(si32)>(), silent);
+	auto options = ObjectCallback::fromNameAndType(name.getModScope(), type, name.String(), std::function<void(si32)>(), silent);
 
 	return getIdentifierImpl(options, silent);
 }
@@ -219,7 +219,7 @@ std::optional<si32> CIdentifierStorage::getIdentifier(const JsonNode & name, boo
 {
 	assert(state != ELoadingState::LOADING);
 
-	auto options = ObjectCallback::fromNameWithType(name.meta, name.String(), std::function<void(si32)>(), silent);
+	auto options = ObjectCallback::fromNameWithType(name.getModScope(), name.String(), std::function<void(si32)>(), silent);
 	return getIdentifierImpl(options, silent);
 }
 
diff --git a/lib/rewardable/Info.cpp b/lib/rewardable/Info.cpp
index 8a6fa89cc..14b73fa6c 100644
--- a/lib/rewardable/Info.cpp
+++ b/lib/rewardable/Info.cpp
@@ -75,7 +75,7 @@ void Rewardable::Info::init(const JsonNode & objectConfig, const std::string & o
 
 	auto loadString = [&](const JsonNode & entry, const TextIdentifier & textID){
 		if (entry.isString() && !entry.String().empty() && entry.String()[0] != '@')
-			VLC->generaltexth->registerString(entry.meta, textID, entry.String());
+			VLC->generaltexth->registerString(entry.getModScope(), textID, entry.String());
 	};
 
 	parameters = objectConfig;
@@ -201,8 +201,8 @@ void Rewardable::Info::configureReward(Rewardable::Configuration & object, CRand
 
 	for ( auto node : source["changeCreatures"].Struct() )
 	{
-		CreatureID from(VLC->identifiers()->getIdentifier(node.second.meta, "creature", node.first).value());
-		CreatureID dest(VLC->identifiers()->getIdentifier(node.second.meta, "creature", node.second.String()).value());
+		CreatureID from(VLC->identifiers()->getIdentifier(node.second.getModScope(), "creature", node.first).value());
+		CreatureID dest(VLC->identifiers()->getIdentifier(node.second.getModScope(), "creature", node.second.String()).value());
 
 		reward.extraComponents.emplace_back(ComponentType::CREATURE, dest);
 
diff --git a/lib/serializer/JsonDeserializer.cpp b/lib/serializer/JsonDeserializer.cpp
index 15d20e989..87cda93d6 100644
--- a/lib/serializer/JsonDeserializer.cpp
+++ b/lib/serializer/JsonDeserializer.cpp
@@ -43,7 +43,7 @@ void JsonDeserializer::serializeInternal(const std::string & fieldName, si32 & v
 		if(rawId < 0) //may be, user has installed the mod into another directory...
 		{
 			auto internalId = vstd::splitStringToPair(identifier, ':').second;
-			auto currentScope = getCurrent().meta;
+			auto currentScope = getCurrent().getModScope();
 			auto actualId = currentScope.length() > 0 ? currentScope + ":" + internalId : internalId;
 
 			rawId = decoder(actualId);
diff --git a/lib/spells/CSpellHandler.cpp b/lib/spells/CSpellHandler.cpp
index 97df5943e..aaf101276 100644
--- a/lib/spells/CSpellHandler.cpp
+++ b/lib/spells/CSpellHandler.cpp
@@ -719,7 +719,7 @@ CSpell * CSpellHandler::loadFromJson(const std::string & scope, const JsonNode &
 	{
 		const int chance = static_cast<int>(node.second.Integer());
 
-		VLC->identifiers()->requestIdentifier(node.second.meta, "faction", node.first, [=](si32 factionID)
+		VLC->identifiers()->requestIdentifier(node.second.getModScope(), "faction", node.first, [=](si32 factionID)
 		{
 			spell->probabilities[FactionID(factionID)] = chance;
 		});
@@ -742,7 +742,7 @@ CSpell * CSpellHandler::loadFromJson(const std::string & scope, const JsonNode &
 	{
 		if(counteredSpell.second.Bool())
 		{
-			VLC->identifiers()->requestIdentifier(counteredSpell.second.meta, "spell", counteredSpell.first, [=](si32 id)
+			VLC->identifiers()->requestIdentifier(counteredSpell.second.getModScope(), "spell", counteredSpell.first, [=](si32 id)
 			{
 				spell->counteredSpells.emplace_back(id);
 			});
diff --git a/lib/spells/TargetCondition.cpp b/lib/spells/TargetCondition.cpp
index 7b9407afe..c55e18719 100644
--- a/lib/spells/TargetCondition.cpp
+++ b/lib/spells/TargetCondition.cpp
@@ -544,7 +544,7 @@ void TargetCondition::loadConditions(const JsonNode & source, bool exclusive, bo
 
 			ModUtility::parseIdentifier(keyValue.first, scope, type, identifier);
 
-			item = itemFactory->createConfigurable(keyValue.second.meta, type, identifier);
+			item = itemFactory->createConfigurable(keyValue.second.getModScope(), type, identifier);
 		}
 
 		if(item)
diff --git a/scripting/lua/LuaScriptingContext.cpp b/scripting/lua/LuaScriptingContext.cpp
index d92e43735..47aacb458 100644
--- a/scripting/lua/LuaScriptingContext.cpp
+++ b/scripting/lua/LuaScriptingContext.cpp
@@ -347,8 +347,8 @@ void LuaContext::pop(JsonNode & value)
 		break;
 	case LUA_TTABLE:
 		{
-			JsonNode asVector(JsonNode::JsonType::DATA_VECTOR);
-			JsonNode asStruct(JsonNode::JsonType::DATA_STRUCT);
+			JsonNode asVector;
+			JsonNode asStruct;
 
 			lua_pushnil(L);  /* first key */
 
diff --git a/scripting/lua/LuaSpellEffect.cpp b/scripting/lua/LuaSpellEffect.cpp
index 484235af6..91db47955 100644
--- a/scripting/lua/LuaSpellEffect.cpp
+++ b/scripting/lua/LuaSpellEffect.cpp
@@ -98,12 +98,12 @@ bool LuaSpellEffect::applicable(Problem & problem, const Mechanics * m, const Ef
 	for(const auto & dest : target)
 	{
 		JsonNode targetData;
-		targetData.Vector().push_back(JsonUtils::intNode(dest.hexValue.hex));
+		targetData.Vector().emplace_back(dest.hexValue.hex);
 
 		if(dest.unitValue)
-			targetData.Vector().push_back(JsonUtils::intNode(dest.unitValue->unitId()));
+			targetData.Vector().emplace_back(dest.unitValue->unitId());
 		else
-			targetData.Vector().push_back(JsonUtils::intNode(-1));
+			targetData.Vector().emplace_back(-1);
 
 		requestP.Vector().push_back(targetData);
 	}
@@ -141,12 +141,12 @@ void LuaSpellEffect::apply(ServerCallback * server, const Mechanics * m, const E
 	for(const auto & dest : target)
 	{
 		JsonNode targetData;
-		targetData.Vector().push_back(JsonUtils::intNode(dest.hexValue.hex));
+		targetData.Vector().emplace_back(dest.hexValue.hex);
 
 		if(dest.unitValue)
-			targetData.Vector().push_back(JsonUtils::intNode(dest.unitValue->unitId()));
+			targetData.Vector().emplace_back(dest.unitValue->unitId());
 		else
-			targetData.Vector().push_back(JsonUtils::intNode(-1));
+			targetData.Vector().emplace_back(-1);
 
 		requestP.Vector().push_back(targetData);
 	}
diff --git a/scripting/lua/LuaStack.cpp b/scripting/lua/LuaStack.cpp
index b406a278d..71f4798c3 100644
--- a/scripting/lua/LuaStack.cpp
+++ b/scripting/lua/LuaStack.cpp
@@ -183,8 +183,8 @@ bool LuaStack::tryGet(int position, JsonNode & value)
 		return tryGet(position, value.String());
 	case LUA_TTABLE:
 		{
-			JsonNode asVector(JsonNode::JsonType::DATA_VECTOR);
-			JsonNode asStruct(JsonNode::JsonType::DATA_STRUCT);
+			JsonNode asVector;
+			JsonNode asStruct;
 
 			lua_pushnil(L);  /* first key */
 
diff --git a/test/entity/CCreatureTest.cpp b/test/entity/CCreatureTest.cpp
index 3ffdd4d7d..590754e73 100644
--- a/test/entity/CCreatureTest.cpp
+++ b/test/entity/CCreatureTest.cpp
@@ -49,7 +49,7 @@ TEST_F(CCreatureTest, RegistersIcons)
 
 TEST_F(CCreatureTest, DISABLED_JsonUpdate)
 {
-	JsonNode data(JsonNode::JsonType::DATA_STRUCT);
+	JsonNode data;
 
 	JsonNode & config = data["config"];
 	config["cost"]["gold"].Integer() = 750;
@@ -106,7 +106,7 @@ TEST_F(CCreatureTest, DISABLED_JsonUpdate)
 
 TEST_F(CCreatureTest, DISABLED_JsonAddBonus)
 {
-	JsonNode data(JsonNode::JsonType::DATA_STRUCT);
+	JsonNode data;
 
 	auto b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::BLOCKS_RETALIATION, BonusSource::CREATURE_ABILITY, 17, BonusSourceID(CreatureID(42)), BonusSubtypeID(CreatureID(43)), BonusValueType::BASE_NUMBER);
 
@@ -132,7 +132,7 @@ TEST_F(CCreatureTest, DISABLED_JsonAddBonus)
 
 TEST_F(CCreatureTest, DISABLED_JsonRemoveBonus)
 {
-	JsonNode data(JsonNode::JsonType::DATA_STRUCT);
+	JsonNode data;
 
 	auto b1 = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::BLOCKS_RETALIATION, BonusSource::CREATURE_ABILITY, 17, BonusSourceID(CreatureID(42)), BonusSubtypeID(CreatureID(43)), BonusValueType::BASE_NUMBER);
 	subject->addNewBonus(b1);
diff --git a/test/game/CGameStateTest.cpp b/test/game/CGameStateTest.cpp
index 29a6a43d5..aff72a61f 100644
--- a/test/game/CGameStateTest.cpp
+++ b/test/game/CGameStateTest.cpp
@@ -420,6 +420,6 @@ TEST_F(CGameStateTest, updateEntity)
 
 	JsonNode actual;
 	EXPECT_CALL(services, updateEntity(Eq(Metatype::CREATURE), Eq(424242), _)).WillOnce(SaveArg<2>(&actual));
-	gameState->updateEntity(Metatype::CREATURE, 424242, JsonUtils::stringNode("TEST"));
+	gameState->updateEntity(Metatype::CREATURE, 424242, JsonNode("TEST"));
 	EXPECT_EQ(actual.String(), "TEST");
 }
diff --git a/test/map/CMapFormatTest.cpp b/test/map/CMapFormatTest.cpp
index 6d6cd9e54..176d5d916 100644
--- a/test/map/CMapFormatTest.cpp
+++ b/test/map/CMapFormatTest.cpp
@@ -95,7 +95,7 @@ static JsonNode getFromArchive(CZipLoader & archive, const std::string & archive
 
 	auto data = archive.load(resource)->readAll();
 
-	JsonNode res(reinterpret_cast<char*>(data.first.get()), data.second);
+	JsonNode res(reinterpret_cast<const std::byte *>(data.first.get()), data.second);
 
 	return res;
 }
diff --git a/test/scripting/LuaSpellEffectAPITest.cpp b/test/scripting/LuaSpellEffectAPITest.cpp
index 78958dfa7..dd3364057 100644
--- a/test/scripting/LuaSpellEffectAPITest.cpp
+++ b/test/scripting/LuaSpellEffectAPITest.cpp
@@ -46,7 +46,7 @@ TEST_F(LuaSpellEffectAPITest, DISABLED_ApplicableOnExpert)
 
 	JsonNode ret = context->callGlobal("applicable", params);
 
-	JsonNode expected = JsonUtils::boolNode(true);
+	JsonNode expected(true);
 
 	JsonComparer cmp(false);
 	cmp.compare("applicable result", ret, expected);
@@ -65,7 +65,7 @@ TEST_F(LuaSpellEffectAPITest, DISABLED_NotApplicableOnAdvanced)
 
 	JsonNode ret = context->callGlobal("applicable", params);
 
-	JsonNode expected = JsonUtils::boolNode(false);
+	JsonNode expected(false);
 
 	JsonComparer cmp(false);
 	cmp.compare("applicable result", ret, expected);
@@ -84,7 +84,7 @@ TEST_F(LuaSpellEffectAPITest, DISABLED_ApplicableOnLeftSideOfField)
 	BattleHex hex(2,2);
 
 	JsonNode first;
-	first.Vector().push_back(JsonUtils::intNode(hex.hex));
+	first.Vector().push_back(JsonNode(hex.hex));
 	first.Vector().push_back(JsonNode());
 
 	JsonNode targets;
@@ -94,7 +94,7 @@ TEST_F(LuaSpellEffectAPITest, DISABLED_ApplicableOnLeftSideOfField)
 
 	JsonNode ret = context->callGlobal("applicableTarget", params);
 
-	JsonNode expected = JsonUtils::boolNode(true);
+	JsonNode expected(true);
 
 	JsonComparer cmp(false);
 	cmp.compare("applicable result", ret, expected);
@@ -113,8 +113,8 @@ TEST_F(LuaSpellEffectAPITest, DISABLED_NotApplicableOnRightSideOfField)
 	BattleHex hex(11,2);
 
 	JsonNode first;
-	first.Vector().push_back(JsonUtils::intNode(hex.hex));
-	first.Vector().push_back(JsonUtils::intNode(-1));
+	first.Vector().emplace_back(hex.hex);
+	first.Vector().emplace_back(-1);
 
 	JsonNode targets;
 	targets.Vector().push_back(first);
@@ -123,7 +123,7 @@ TEST_F(LuaSpellEffectAPITest, DISABLED_NotApplicableOnRightSideOfField)
 
 	JsonNode ret = context->callGlobal("applicableTarget", params);
 
-	JsonNode expected = JsonUtils::boolNode(false);
+	JsonNode expected(false);
 
 	JsonComparer cmp(false);
 	cmp.compare("applicable result", ret, expected);
@@ -138,14 +138,14 @@ TEST_F(LuaSpellEffectAPITest, DISABLED_ApplyMoveUnit)
 	BattleHex hex1(11,2);
 
 	JsonNode unit;
-	unit.Vector().push_back(JsonUtils::intNode(hex1.hex));
-	unit.Vector().push_back(JsonUtils::intNode(42));
+	unit.Vector().emplace_back(hex1.hex);
+	unit.Vector().emplace_back(42);
 
 	BattleHex hex2(5,4);
 
 	JsonNode destination;
-	destination.Vector().push_back(JsonUtils::intNode(hex2.hex));
-	destination.Vector().push_back(JsonUtils::intNode(-1));
+	destination.Vector().emplace_back(hex2.hex);
+	destination.Vector().emplace_back(-1);
 
 	JsonNode targets;
 	targets.Vector().push_back(unit);
diff --git a/test/scripting/LuaSpellEffectTest.cpp b/test/scripting/LuaSpellEffectTest.cpp
index b917c9746..01a95b1a3 100644
--- a/test/scripting/LuaSpellEffectTest.cpp
+++ b/test/scripting/LuaSpellEffectTest.cpp
@@ -91,7 +91,7 @@ public:
 
 	JsonNode saveRequest(const std::string &, const JsonNode & parameters)
 	{
-		JsonNode response = JsonUtils::boolNode(true);
+		JsonNode response(true);
 
 		request = parameters;
 		return response;
@@ -99,7 +99,7 @@ public:
 
 	JsonNode saveRequest2(ServerCallback *, const std::string &, const JsonNode & parameters)
 	{
-		JsonNode response = JsonUtils::boolNode(true);
+		JsonNode response(true);
 
 		request = parameters;
 		return response;
@@ -123,7 +123,7 @@ TEST_F(LuaSpellEffectTest, ApplicableRedirected)
 {
 	setDefaultExpectations();
 
-	JsonNode response = JsonUtils::boolNode(true);
+	JsonNode response(true);
 
 	EXPECT_CALL(*contextMock, callGlobal(Eq("applicable"),_)).WillOnce(Return(response));//TODO: check call parameter
 
@@ -154,12 +154,12 @@ TEST_F(LuaSpellEffectTest, ApplicableTargetRedirected)
 
 
 	JsonNode first;
-	first.Vector().push_back(JsonUtils::intNode(hex1.hex));
-	first.Vector().push_back(JsonUtils::intNode(id1));
+	first.Vector().push_back(JsonNode(hex1.hex));
+	first.Vector().push_back(JsonNode(id1));
 
 	JsonNode second;
-	second.Vector().push_back(JsonUtils::intNode(hex2.hex));
-	second.Vector().push_back(JsonUtils::intNode(-1));
+	second.Vector().push_back(JsonNode(hex2.hex));
+	second.Vector().push_back(JsonNode(-1));
 
 	JsonNode targets;
 	targets.Vector().push_back(first);
@@ -193,8 +193,8 @@ TEST_F(LuaSpellEffectTest, ApplyRedirected)
 	subject->apply(&serverMock, &mechanicsMock, target);
 
 	JsonNode first;
-	first.Vector().push_back(JsonUtils::intNode(hex1.hex));
-	first.Vector().push_back(JsonUtils::intNode(id1));
+	first.Vector().push_back(JsonNode(hex1.hex));
+	first.Vector().push_back(JsonNode(id1));
 
 	JsonNode targets;
 	targets.Vector().push_back(first);
diff --git a/test/scripting/ScriptFixture.cpp b/test/scripting/ScriptFixture.cpp
index aabcea131..0ff6e3b2b 100644
--- a/test/scripting/ScriptFixture.cpp
+++ b/test/scripting/ScriptFixture.cpp
@@ -23,7 +23,7 @@ ScriptFixture::~ScriptFixture() = default;
 
 void ScriptFixture::loadScriptFromFile(const std::string & path)
 {
-	JsonNode scriptConfig(JsonNode::JsonType::DATA_STRUCT);
+	JsonNode scriptConfig;
 	scriptConfig["source"].String() = path;
 	loadScript(scriptConfig);
 }
diff --git a/test/spells/TargetConditionTest.cpp b/test/spells/TargetConditionTest.cpp
index 2f6f604fb..7ed5d3ccf 100644
--- a/test/spells/TargetConditionTest.cpp
+++ b/test/spells/TargetConditionTest.cpp
@@ -122,7 +122,7 @@ TEST_F(TargetConditionTest, SerializesCorrectly)
 
 	EXPECT_CALL(factoryMock, createConfigurable(Eq(""), Eq("bonus"), Eq("UNDEAD"))).WillOnce(Return(normalItem));
 
-	JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+	JsonNode config;
 	config["noneOf"]["bonus.NON_LIVING"].String() = "normal";
 	config["anyOf"]["bonus.SIEGE_WEAPON"].String() = "absolute";
 	config["allOf"]["bonus.UNDEAD"].String() = "normal";
diff --git a/test/spells/effects/CatapultTest.cpp b/test/spells/effects/CatapultTest.cpp
index 690d9cb5c..1cb55c5f2 100644
--- a/test/spells/effects/CatapultTest.cpp
+++ b/test/spells/effects/CatapultTest.cpp
@@ -116,7 +116,7 @@ private:
 TEST_F(CatapultApplyTest, DISABLED_DamageToIntactPart)
 {
 	{
-		JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode config;
 		config["targetsToAttack"].Integer() = 1;
 		config["chanceToNormalHit"].Integer() = 100;
 		EffectFixture::setupEffect(config);
diff --git a/test/spells/effects/CloneTest.cpp b/test/spells/effects/CloneTest.cpp
index 810824b6b..b68124242 100644
--- a/test/spells/effects/CloneTest.cpp
+++ b/test/spells/effects/CloneTest.cpp
@@ -40,7 +40,7 @@ protected:
 TEST_F(CloneTest, ApplicableToValidTarget)
 {
 	{
-		JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode config;
 		config["maxTier"].Integer() = 7;
 		EffectFixture::setupEffect(config);
 	}
diff --git a/test/spells/effects/DamageTest.cpp b/test/spells/effects/DamageTest.cpp
index a8bae9734..227764405 100644
--- a/test/spells/effects/DamageTest.cpp
+++ b/test/spells/effects/DamageTest.cpp
@@ -147,7 +147,7 @@ TEST_F(DamageApplyTest, DISABLED_DoesDamageByPercent)
 	using namespace ::battle;
 
 	{
-		JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode config;
 		config["killByPercentage"].Bool() = true;
 		EffectFixture::setupEffect(config);
 	}
@@ -192,7 +192,7 @@ TEST_F(DamageApplyTest, DISABLED_DoesDamageByCount)
 	using namespace ::battle;
 
 	{
-		JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode config;
 		config["killByCount"].Bool() = true;
 		EffectFixture::setupEffect(config);
 	}
diff --git a/test/spells/effects/DispelTest.cpp b/test/spells/effects/DispelTest.cpp
index 5d05ea81a..fb53586b3 100644
--- a/test/spells/effects/DispelTest.cpp
+++ b/test/spells/effects/DispelTest.cpp
@@ -68,7 +68,7 @@ class DispelTest : public DispelFixture
 TEST_F(DispelTest, DISABLED_ApplicableToAliveUnitWithTimedEffect)
 {
 	{
-		JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode config;
 		config["dispelNegative"].Bool() = true;
 		EffectFixture::setupEffect(config);
 	}
@@ -94,7 +94,7 @@ TEST_F(DispelTest, DISABLED_ApplicableToAliveUnitWithTimedEffect)
 TEST_F(DispelTest, DISABLED_IgnoresOwnEffects)
 {
 	{
-		JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode config;
 		config["dispelPositive"].Bool() = true;
 		config["dispelNegative"].Bool() = true;
 		config["dispelNeutral"].Bool() = true;
@@ -165,7 +165,7 @@ public:
 TEST_F(DispelApplyTest, DISABLED_RemovesEffects)
 {
 	{
-		JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode config;
 		config["dispelPositive"].Bool() = true;
 		config["dispelNegative"].Bool() = true;
 		config["dispelNeutral"].Bool() = true;
diff --git a/test/spells/effects/HealTest.cpp b/test/spells/effects/HealTest.cpp
index d2479951c..8cfdb396b 100644
--- a/test/spells/effects/HealTest.cpp
+++ b/test/spells/effects/HealTest.cpp
@@ -77,7 +77,7 @@ TEST_F(HealTest, ApplicableToWoundedUnit)
 TEST_F(HealTest, ApplicableIfActuallyResurrects)
 {
 	{
-		JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode config;
 		config["healLevel"].String() = "resurrect";
 		config["minFullUnits"].Integer() = 5;
 		EffectFixture::setupEffect(config);
@@ -104,7 +104,7 @@ TEST_F(HealTest, ApplicableIfActuallyResurrects)
 TEST_F(HealTest, NotApplicableIfNotEnoughCasualties)
 {
 	{
-		JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode config;
 		config["healLevel"].String() = "resurrect";
 		config["minFullUnits"].Integer() = 1;
 		EffectFixture::setupEffect(config);
@@ -130,7 +130,7 @@ TEST_F(HealTest, NotApplicableIfNotEnoughCasualties)
 TEST_F(HealTest, NotApplicableIfResurrectsLessThanRequired)
 {
 	{
-		JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode config;
 		config["healLevel"].String() = "resurrect";
 		config["minFullUnits"].Integer() = 5;
 		EffectFixture::setupEffect(config);
@@ -156,7 +156,7 @@ TEST_F(HealTest, NotApplicableIfResurrectsLessThanRequired)
 TEST_F(HealTest, ApplicableToDeadUnit)
 {
 	{
-		JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode config;
 		config["healLevel"].String() = "resurrect";
 		EffectFixture::setupEffect(config);
 	}
@@ -187,7 +187,7 @@ TEST_F(HealTest, ApplicableToDeadUnit)
 TEST_F(HealTest, DISABLED_NotApplicableIfDeadUnitIsBlocked)
 {
 	{
-		JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode config;
 		config["healLevel"].String() = "resurrect";
 		EffectFixture::setupEffect(config);
 	}
@@ -224,7 +224,7 @@ TEST_F(HealTest, DISABLED_NotApplicableIfDeadUnitIsBlocked)
 TEST_F(HealTest, DISABLED_ApplicableWithAnotherDeadUnitInSamePosition)
 {
 	{
-		JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode config;
 		config["healLevel"].String() = "resurrect";
 		EffectFixture::setupEffect(config);
 	}
@@ -261,7 +261,7 @@ TEST_F(HealTest, DISABLED_ApplicableWithAnotherDeadUnitInSamePosition)
 TEST_F(HealTest, NotApplicableIfEffectValueTooLow)
 {
 	{
-		JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode config;
 		config["minFullUnits"].Integer() = 1;
 		EffectFixture::setupEffect(config);
 	}
@@ -328,7 +328,7 @@ protected:
 TEST_P(HealApplyTest, DISABLED_Heals)
 {
 	{
-		JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode config;
 		config["healLevel"].String() = HEAL_LEVEL_MAP.at(static_cast<size_t>(healLevel));
 		config["healPower"].String() = HEAL_POWER_MAP.at(static_cast<size_t>(healPower));
 		EffectFixture::setupEffect(config);
diff --git a/test/spells/effects/SacrificeTest.cpp b/test/spells/effects/SacrificeTest.cpp
index 2bde689ef..40c04bc4e 100644
--- a/test/spells/effects/SacrificeTest.cpp
+++ b/test/spells/effects/SacrificeTest.cpp
@@ -39,7 +39,7 @@ protected:
 		EffectFixture::setUp();
 
 		{
-			JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+			JsonNode config;
 			config["healLevel"].String() = "resurrect";
 			EffectFixture::setupEffect(config);
 		}
@@ -146,7 +146,7 @@ protected:
 		EffectFixture::setUp();
 
 		{
-			JsonNode config(JsonNode::JsonType::DATA_STRUCT);
+			JsonNode config;
 			config["healLevel"].String() = "resurrect";
 			config["healPower"].String() = "permanent";
 			EffectFixture::setupEffect(config);
diff --git a/test/spells/effects/SummonTest.cpp b/test/spells/effects/SummonTest.cpp
index 2dfbfc659..fbc322340 100644
--- a/test/spells/effects/SummonTest.cpp
+++ b/test/spells/effects/SummonTest.cpp
@@ -73,7 +73,7 @@ protected:
 
 		toSummon = creature1;
 
-		JsonNode options(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode options;
 		options["id"].String() = "airElemental";
 		options["exclusive"].Bool() = exclusive;
 		options["summonSameUnit"].Bool() = summonSameUnit;
@@ -202,7 +202,7 @@ protected:
 		permanent = ::testing::get<0>(GetParam());
 		summonByHealth = ::testing::get<1>(GetParam());
 
-		JsonNode options(JsonNode::JsonType::DATA_STRUCT);
+		JsonNode options;
 		options["id"].String() = "airElemental";
 		options["permanent"].Bool() = permanent;
 		options["summonByHealth"].Bool() = summonByHealth;
diff --git a/test/spells/effects/TimedTest.cpp b/test/spells/effects/TimedTest.cpp
index e96f3d476..541a35ecf 100644
--- a/test/spells/effects/TimedTest.cpp
+++ b/test/spells/effects/TimedTest.cpp
@@ -77,11 +77,11 @@ TEST_P(TimedApplyTest, DISABLED_ChangesBonuses)
 	Bonus testBonus2(BonusDuration::N_TURNS, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 3, BonusSourceID(), BonusSubtypeID(PrimarySkill::KNOWLEDGE));
 	testBonus2.turnsRemain = 4;
 
-	JsonNode options(JsonNode::JsonType::DATA_STRUCT);
+	JsonNode options;
 	options["cumulative"].Bool() = cumulative;
 	options["bonus"]["test1"] = testBonus1.toJsonNode();
 	options["bonus"]["test2"] = testBonus2.toJsonNode();
-	options.setMeta(ModScope::scopeBuiltin());
+	options.setModScope(ModScope::scopeBuiltin());
 	setupEffect(options);
 
 	const uint32_t unitId = 42;