mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
commit
54fefd34c7
@ -243,7 +243,7 @@ int main(int argc, char * argv[])
|
||||
|
||||
// Initialize logging based on settings
|
||||
logConfig->configure();
|
||||
logGlobal->debug("settings = %s", settings.toJsonNode().toJson());
|
||||
logGlobal->debug("settings = %s", settings.toJsonNode().toString());
|
||||
|
||||
// Some basic data validation to produce better error messages in cases of incorrect install
|
||||
auto testFile = [](std::string filename, std::string message)
|
||||
|
@ -248,13 +248,13 @@ 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, ":", "_");
|
||||
|
||||
const boost::filesystem::path filePath = contentOutPath / (name + ".json");
|
||||
std::ofstream file(filePath.c_str());
|
||||
file << object.toJson();
|
||||
file << object.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -358,7 +358,7 @@ void ClientCommandManager::handleBonusesCommand(std::istringstream & singleWordB
|
||||
auto format = [outputFormat](const BonusList & b) -> std::string
|
||||
{
|
||||
if(outputFormat == "json")
|
||||
return b.toJsonNode().toJson(true);
|
||||
return b.toJsonNode().toCompactString();
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << b;
|
||||
|
@ -273,7 +273,7 @@ void GlobalLobbyClient::onDisconnected(const std::shared_ptr<INetworkConnection>
|
||||
|
||||
void GlobalLobbyClient::sendMessage(const JsonNode & data)
|
||||
{
|
||||
networkConnection->sendPacket(data.toBytes(true));
|
||||
networkConnection->sendPacket(data.toBytes());
|
||||
}
|
||||
|
||||
void GlobalLobbyClient::sendOpenPublicRoom()
|
||||
@ -362,5 +362,5 @@ void GlobalLobbyClient::sendProxyConnectionLogin(const NetworkConnectionPtr & ne
|
||||
toSend["accountCookie"] = settings["lobby"]["accountCookie"];
|
||||
toSend["gameRoomID"] = settings["lobby"]["roomID"];
|
||||
|
||||
netConnection->sendPacket(toSend.toBytes(true));
|
||||
netConnection->sendPacket(toSend.toBytes());
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ void CAnimation::initFromJson(const JsonNode & config)
|
||||
std::string basepath;
|
||||
basepath = config["basepath"].String();
|
||||
|
||||
JsonNode base(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode base;
|
||||
base["margins"] = config["margins"];
|
||||
base["width"] = config["width"];
|
||||
base["height"] = config["height"];
|
||||
@ -114,7 +114,7 @@ void CAnimation::initFromJson(const JsonNode & config)
|
||||
|
||||
for(const JsonNode & frame : group["frames"].Vector())
|
||||
{
|
||||
JsonNode toAdd(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode toAdd;
|
||||
JsonUtils::inherit(toAdd, base);
|
||||
toAdd["file"].String() = basepath + frame.String();
|
||||
source[groupID].push_back(toAdd);
|
||||
@ -129,7 +129,7 @@ void CAnimation::initFromJson(const JsonNode & config)
|
||||
if (source[group].size() <= frame)
|
||||
source[group].resize(frame+1);
|
||||
|
||||
JsonNode toAdd(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode toAdd;
|
||||
JsonUtils::inherit(toAdd, base);
|
||||
toAdd["file"].String() = basepath + node["file"].String();
|
||||
source[group][frame] = toAdd;
|
||||
@ -191,7 +191,7 @@ void CAnimation::init()
|
||||
std::unique_ptr<ui8[]> textData(new ui8[stream->getSize()]);
|
||||
stream->read(textData.get(), stream->getSize());
|
||||
|
||||
const JsonNode config((char*)textData.get(), stream->getSize());
|
||||
const JsonNode config(reinterpret_cast<const std::byte*>(textData.get()), stream->getSize());
|
||||
|
||||
initFromJson(config);
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ void Graphics::initializeBattleGraphics()
|
||||
if(!CResourceHandler::get(mod)->existsResource(ResourcePath("config/battles_graphics.json")))
|
||||
continue;
|
||||
|
||||
const JsonNode config(mod, JsonPath::builtin("config/battles_graphics.json"));
|
||||
const JsonNode config(JsonPath::builtin("config/battles_graphics.json"), mod);
|
||||
|
||||
//initialization of AC->def name mapping
|
||||
if(!config["ac_mapping"].isNull())
|
||||
|
@ -93,7 +93,7 @@
|
||||
"map" : {
|
||||
"type" : "string",
|
||||
"description" : ".def file for adventure map",
|
||||
"format" : "defFile"
|
||||
"format" : "animationFile"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -133,12 +133,12 @@
|
||||
"animation" : {
|
||||
"type" : "string",
|
||||
"description" : "File with animation of this creature in battles",
|
||||
"format" : "defFile"
|
||||
"format" : "animationFile"
|
||||
},
|
||||
"map" : {
|
||||
"type" : "string",
|
||||
"description" : "File with animation of this creature on adventure map",
|
||||
"format" : "defFile"
|
||||
"format" : "animationFile"
|
||||
},
|
||||
"mapMask" : {
|
||||
"type" : "array",
|
||||
@ -184,7 +184,7 @@
|
||||
"projectile" : {
|
||||
"type" : "string",
|
||||
"description" : "Path to projectile animation",
|
||||
"format" : "defFile"
|
||||
"format" : "animationFile"
|
||||
},
|
||||
"ray" : {
|
||||
"type" : "array",
|
||||
|
@ -29,7 +29,14 @@
|
||||
"battleImage" : {
|
||||
"type" : "string",
|
||||
"description" : "Custom animation to be used on battle, overrides hero class property",
|
||||
"format" : "defFile"
|
||||
"format" : "animationFile"
|
||||
},
|
||||
"compatibilityIdentifiers" : {
|
||||
"type" : "array",
|
||||
"items" : {
|
||||
"type" : "string",
|
||||
},
|
||||
"description" : "Additional identifiers that may refer to this object, to provide compatibility after object has been renamed"
|
||||
},
|
||||
"images" : {
|
||||
"type" : "object",
|
||||
|
@ -42,12 +42,12 @@
|
||||
"female" : {
|
||||
"type" : "string",
|
||||
"description" : "Female version",
|
||||
"format" : "defFile"
|
||||
"format" : "animationFile"
|
||||
},
|
||||
"male" : {
|
||||
"type" : "string",
|
||||
"description" : "Male version",
|
||||
"format" : "defFile"
|
||||
"format" : "animationFile"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,12 +9,12 @@
|
||||
"animation" : {
|
||||
"type" : "string",
|
||||
"description" : "Path to def file with animation of this object",
|
||||
"format" : "defFile"
|
||||
"format" : "animationFile"
|
||||
},
|
||||
"editorAnimation" : {
|
||||
"type" : "string",
|
||||
"description" : "Optional path to def file with animation of this object to use in map editor",
|
||||
"format" : "defFile"
|
||||
"format" : "animationFile"
|
||||
},
|
||||
"visitableFrom" : {
|
||||
"type" : "array",
|
||||
|
@ -45,7 +45,7 @@
|
||||
"type" : "string",
|
||||
"description" : "Image resource",
|
||||
"anyOf" : [
|
||||
{ "format" : "defFile" },
|
||||
{ "format" : "animationFile" },
|
||||
{ "format" : "imageFile" }
|
||||
]
|
||||
},
|
||||
|
@ -20,7 +20,7 @@
|
||||
{
|
||||
"type" : "string",
|
||||
"description" : "Name of file with river graphics",
|
||||
"format" : "defFile"
|
||||
"format" : "animationFile"
|
||||
},
|
||||
"delta" :
|
||||
{
|
||||
|
@ -20,7 +20,7 @@
|
||||
{
|
||||
"type" : "string",
|
||||
"description" : "Name of file with road graphics",
|
||||
"format" : "defFile"
|
||||
"format" : "animationFile"
|
||||
},
|
||||
"moveCost" :
|
||||
{
|
||||
|
@ -15,13 +15,13 @@
|
||||
{
|
||||
//assumed verticalPosition: top
|
||||
"type" : "string",
|
||||
"format" : "defFile"
|
||||
"format" : "animationFile"
|
||||
},
|
||||
{
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"verticalPosition" : {"type" : "string", "enum" :["top","bottom"]},
|
||||
"defName" : {"type" : "string", "format" : "defFile"},
|
||||
"defName" : {"type" : "string", "format" : "animationFile"},
|
||||
"effectName" : { "type" : "string" }
|
||||
},
|
||||
"additionalProperties" : false
|
||||
@ -41,7 +41,7 @@
|
||||
"items" : {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"defName" : {"type" : "string", "format" : "defFile"},
|
||||
"defName" : {"type" : "string", "format" : "animationFile"},
|
||||
"minimumAngle" : {"type" : "number", "minimum" : 0}
|
||||
},
|
||||
"additionalProperties" : false
|
||||
|
@ -35,7 +35,7 @@
|
||||
{
|
||||
"type" : "string",
|
||||
"description" : "Name of file with graphicks",
|
||||
"format" : "defFile"
|
||||
"format" : "animationFile"
|
||||
},
|
||||
"rockTerrain" :
|
||||
{
|
||||
|
@ -89,7 +89,7 @@ QVariant JsonFromFile(QString filename)
|
||||
}
|
||||
|
||||
const auto data = file.readAll();
|
||||
JsonNode node(data.data(), data.size());
|
||||
JsonNode node(reinterpret_cast<const std::byte*>(data.data()), data.size());
|
||||
return toVariant(node);
|
||||
}
|
||||
|
||||
@ -116,7 +116,7 @@ JsonNode toJson(QVariant object)
|
||||
void JsonToFile(QString filename, QVariant object)
|
||||
{
|
||||
std::fstream file(qstringToPath(filename).c_str(), std::ios::out | std::ios_base::binary);
|
||||
file << toJson(object).toJson();
|
||||
file << toJson(object).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ UpdateDialog::UpdateDialog(bool calledManually, QWidget *parent):
|
||||
}
|
||||
|
||||
auto byteArray = response->readAll();
|
||||
JsonNode node(byteArray.constData(), byteArray.size());
|
||||
JsonNode node(reinterpret_cast<const std::byte*>(byteArray.constData()), byteArray.size());
|
||||
loadFromJson(node);
|
||||
});
|
||||
}
|
||||
|
@ -350,8 +350,7 @@ std::vector<JsonNode> CArtHandler::loadLegacyData()
|
||||
{
|
||||
if(parser.readString() == "x")
|
||||
{
|
||||
artData["slot"].Vector().push_back(JsonNode());
|
||||
artData["slot"].Vector().back().String() = artSlot;
|
||||
artData["slot"].Vector().emplace_back(artSlot);
|
||||
}
|
||||
}
|
||||
artData["class"].String() = classes.at(parser.readString()[0]);
|
||||
@ -461,7 +460,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 +468,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
|
||||
|
@ -90,7 +90,7 @@ void SettingsStorage::invalidateNode(const std::vector<std::string> &changedPath
|
||||
JsonUtils::minimize(savedConf, schema);
|
||||
|
||||
std::fstream file(CResourceHandler::get()->getResourceName(JsonPath::builtin(dataFilename))->c_str(), std::ofstream::out | std::ofstream::trunc);
|
||||
file << savedConf.toJson();
|
||||
file << savedConf.toString();
|
||||
}
|
||||
|
||||
JsonNode & SettingsStorage::getNode(const std::vector<std::string> & path)
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
});
|
||||
|
||||
|
@ -405,6 +405,7 @@ set(lib_HEADERS
|
||||
filesystem/ResourcePath.h
|
||||
|
||||
json/JsonBonus.h
|
||||
json/JsonFormatException.h
|
||||
json/JsonNode.h
|
||||
json/JsonParser.h
|
||||
json/JsonRandom.h
|
||||
|
@ -168,7 +168,7 @@ std::vector<JsonNode> CSkillHandler::loadLegacyData()
|
||||
std::vector<JsonNode> legacyData;
|
||||
for(int id = 0; id < GameConstants::SKILL_QUANTITY; id++)
|
||||
{
|
||||
JsonNode skillNode(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode skillNode;
|
||||
skillNode["name"].String() = skillNames[id];
|
||||
for(int level = 1; level < NSecondarySkill::levels.size(); level++)
|
||||
{
|
||||
|
@ -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"]);
|
||||
}
|
||||
|
||||
@ -1201,7 +1201,7 @@ void CTownHandler::initializeRequirements()
|
||||
{
|
||||
logMod->error("Unexpected length of town buildings requirements: %d", node.Vector().size());
|
||||
logMod->error("Entry contains: ");
|
||||
logMod->error(node.toJson());
|
||||
logMod->error(node.toString());
|
||||
}
|
||||
|
||||
auto index = VLC->identifiers()->getIdentifier(requirement.town->getBuildingScope(), node[0]);
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include "../TerrainHandler.h"
|
||||
#include "../constants/StringConstants.h"
|
||||
#include "../battle/BattleInfo.h"
|
||||
#include "../json/JsonUtils.h"
|
||||
#include "../modding/ModUtility.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
@ -72,20 +71,20 @@ si32 CAddInfo::operator[](size_type pos) const
|
||||
|
||||
std::string CAddInfo::toString() const
|
||||
{
|
||||
return toJsonNode().toJson(true);
|
||||
return toJsonNode().toCompactString();
|
||||
}
|
||||
|
||||
JsonNode CAddInfo::toJsonNode() const
|
||||
{
|
||||
if(size() < 2)
|
||||
{
|
||||
return JsonUtils::intNode(operator[](0));
|
||||
return JsonNode(operator[](0));
|
||||
}
|
||||
else
|
||||
{
|
||||
JsonNode node(JsonNode::JsonType::DATA_VECTOR);
|
||||
JsonNode node;
|
||||
for(si32 value : *this)
|
||||
node.Vector().push_back(JsonUtils::intNode(value));
|
||||
node.Vector().emplace_back(value);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
@ -143,7 +142,7 @@ static JsonNode additionalInfoToJson(BonusType type, CAddInfo addInfo)
|
||||
switch(type)
|
||||
{
|
||||
case BonusType::SPECIAL_UPGRADE:
|
||||
return JsonUtils::stringNode(ModUtility::makeFullIdentifier("", "creature", CreatureID::encode(addInfo[0])));
|
||||
return JsonNode(ModUtility::makeFullIdentifier("", "creature", CreatureID::encode(addInfo[0])));
|
||||
default:
|
||||
return addInfo.toJsonNode();
|
||||
}
|
||||
@ -151,7 +150,7 @@ static JsonNode additionalInfoToJson(BonusType type, CAddInfo addInfo)
|
||||
|
||||
JsonNode Bonus::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode root;
|
||||
// only add values that might reasonably be found in config files
|
||||
root["type"].String() = vstd::findKey(bonusNameMap, type);
|
||||
if(subtype != BonusSubtypeID())
|
||||
|
@ -67,13 +67,13 @@ namespace BonusDuration
|
||||
}
|
||||
if(durationNames.size() == 1)
|
||||
{
|
||||
return JsonUtils::stringNode(durationNames[0]);
|
||||
return JsonNode(durationNames[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
JsonNode node(JsonNode::JsonType::DATA_VECTOR);
|
||||
JsonNode node;
|
||||
for(const std::string & dur : durationNames)
|
||||
node.Vector().push_back(JsonUtils::stringNode(dur));
|
||||
node.Vector().emplace_back(dur);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ int BonusList::valOfBonuses(const CSelector &select) const
|
||||
|
||||
JsonNode BonusList::toJsonNode() const
|
||||
{
|
||||
JsonNode node(JsonNode::JsonType::DATA_VECTOR);
|
||||
JsonNode node;
|
||||
for(const std::shared_ptr<Bonus> & b : bonuses)
|
||||
node.Vector().push_back(b->toJsonNode());
|
||||
return node;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -92,7 +92,7 @@ std::string ILimiter::toString() const
|
||||
|
||||
JsonNode ILimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode root;
|
||||
root["type"].String() = toString();
|
||||
return root;
|
||||
}
|
||||
@ -127,11 +127,11 @@ std::string CCreatureTypeLimiter::toString() const
|
||||
|
||||
JsonNode CCreatureTypeLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode root;
|
||||
|
||||
root["type"].String() = "CREATURE_TYPE_LIMITER";
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(creature->getJsonKey()));
|
||||
root["parameters"].Vector().push_back(JsonUtils::boolNode(includeUpgrades));
|
||||
root["parameters"].Vector().emplace_back(creature->getJsonKey());
|
||||
root["parameters"].Vector().emplace_back(includeUpgrades);
|
||||
|
||||
return root;
|
||||
}
|
||||
@ -199,16 +199,16 @@ std::string HasAnotherBonusLimiter::toString() const
|
||||
|
||||
JsonNode HasAnotherBonusLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode root;
|
||||
std::string typeName = vstd::findKey(bonusNameMap, type);
|
||||
auto sourceTypeName = vstd::findKey(bonusSourceMap, source);
|
||||
|
||||
root["type"].String() = "HAS_ANOTHER_BONUS_LIMITER";
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(typeName));
|
||||
root["parameters"].Vector().emplace_back(typeName);
|
||||
if(isSubtypeRelevant)
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(subtype.toString()));
|
||||
root["parameters"].Vector().emplace_back(subtype.toString());
|
||||
if(isSourceRelevant)
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(sourceTypeName));
|
||||
root["parameters"].Vector().emplace_back(sourceTypeName);
|
||||
|
||||
return root;
|
||||
}
|
||||
@ -233,11 +233,11 @@ UnitOnHexLimiter::UnitOnHexLimiter(const std::set<BattleHex> & applicableHexes):
|
||||
|
||||
JsonNode UnitOnHexLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode root;
|
||||
|
||||
root["type"].String() = "UNIT_ON_HEXES";
|
||||
for(const auto & hex : applicableHexes)
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(hex));
|
||||
root["parameters"].Vector().emplace_back(hex);
|
||||
|
||||
return root;
|
||||
}
|
||||
@ -278,11 +278,11 @@ std::string CreatureTerrainLimiter::toString() const
|
||||
|
||||
JsonNode CreatureTerrainLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode root;
|
||||
|
||||
root["type"].String() = "CREATURE_TERRAIN_LIMITER";
|
||||
auto terrainName = VLC->terrainTypeHandler->getById(terrainType)->getJsonKey();
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(terrainName));
|
||||
root["parameters"].Vector().emplace_back(terrainName);
|
||||
|
||||
return root;
|
||||
}
|
||||
@ -324,10 +324,10 @@ std::string FactionLimiter::toString() const
|
||||
|
||||
JsonNode FactionLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode root;
|
||||
|
||||
root["type"].String() = "FACTION_LIMITER";
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(VLC->factions()->getById(faction)->getJsonKey()));
|
||||
root["parameters"].Vector().emplace_back(VLC->factions()->getById(faction)->getJsonKey());
|
||||
|
||||
return root;
|
||||
}
|
||||
@ -354,11 +354,11 @@ std::string CreatureLevelLimiter::toString() const
|
||||
|
||||
JsonNode CreatureLevelLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode root;
|
||||
|
||||
root["type"].String() = "CREATURE_LEVEL_LIMITER";
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(minLevel));
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(maxLevel));
|
||||
root["parameters"].Vector().emplace_back(minLevel);
|
||||
root["parameters"].Vector().emplace_back(maxLevel);
|
||||
|
||||
return root;
|
||||
}
|
||||
@ -392,10 +392,10 @@ std::string CreatureAlignmentLimiter::toString() const
|
||||
|
||||
JsonNode CreatureAlignmentLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode root;
|
||||
|
||||
root["type"].String() = "CREATURE_ALIGNMENT_LIMITER";
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(GameConstants::ALIGNMENT_NAMES[vstd::to_underlying(alignment)]));
|
||||
root["parameters"].Vector().emplace_back(GameConstants::ALIGNMENT_NAMES[vstd::to_underlying(alignment)]);
|
||||
|
||||
return root;
|
||||
}
|
||||
@ -450,8 +450,8 @@ void AggregateLimiter::add(const TLimiterPtr & limiter)
|
||||
|
||||
JsonNode AggregateLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode result(JsonNode::JsonType::DATA_VECTOR);
|
||||
result.Vector().push_back(JsonUtils::stringNode(getAggregator()));
|
||||
JsonNode result;
|
||||
result.Vector().emplace_back(getAggregator());
|
||||
for(const auto & l : limiters)
|
||||
result.Vector().push_back(l->toJsonNode());
|
||||
return result;
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "Updaters.h"
|
||||
#include "Limiters.h"
|
||||
|
||||
#include "../json/JsonUtils.h"
|
||||
#include "../json/JsonNode.h"
|
||||
#include "../mapObjects/CGHeroInstance.h"
|
||||
#include "../CStack.h"
|
||||
|
||||
@ -39,7 +39,7 @@ std::string IUpdater::toString() const
|
||||
|
||||
JsonNode IUpdater::toJsonNode() const
|
||||
{
|
||||
return JsonNode(JsonNode::JsonType::DATA_NULL);
|
||||
return JsonNode();
|
||||
}
|
||||
|
||||
GrowsWithLevelUpdater::GrowsWithLevelUpdater(int valPer20, int stepSize) : valPer20(valPer20), stepSize(stepSize)
|
||||
@ -69,12 +69,12 @@ std::string GrowsWithLevelUpdater::toString() const
|
||||
|
||||
JsonNode GrowsWithLevelUpdater::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode root;
|
||||
|
||||
root["type"].String() = "GROWS_WITH_LEVEL";
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(valPer20));
|
||||
root["parameters"].Vector().emplace_back(valPer20);
|
||||
if(stepSize > 1)
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(stepSize));
|
||||
root["parameters"].Vector().emplace_back(stepSize);
|
||||
|
||||
return root;
|
||||
}
|
||||
@ -98,7 +98,7 @@ std::string TimesHeroLevelUpdater::toString() const
|
||||
|
||||
JsonNode TimesHeroLevelUpdater::toJsonNode() const
|
||||
{
|
||||
return JsonUtils::stringNode("TIMES_HERO_LEVEL");
|
||||
return JsonNode("TIMES_HERO_LEVEL");
|
||||
}
|
||||
|
||||
ArmyMovementUpdater::ArmyMovementUpdater():
|
||||
@ -141,13 +141,13 @@ std::string ArmyMovementUpdater::toString() const
|
||||
|
||||
JsonNode ArmyMovementUpdater::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode root;
|
||||
|
||||
root["type"].String() = "ARMY_MOVEMENT";
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(base));
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(divider));
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(multiplier));
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(max));
|
||||
root["parameters"].Vector().emplace_back(base);
|
||||
root["parameters"].Vector().emplace_back(divider);
|
||||
root["parameters"].Vector().emplace_back(multiplier);
|
||||
root["parameters"].Vector().emplace_back(max);
|
||||
|
||||
return root;
|
||||
}
|
||||
@ -183,7 +183,7 @@ std::string TimesStackLevelUpdater::toString() const
|
||||
|
||||
JsonNode TimesStackLevelUpdater::toJsonNode() const
|
||||
{
|
||||
return JsonUtils::stringNode("TIMES_STACK_LEVEL");
|
||||
return JsonNode("TIMES_STACK_LEVEL");
|
||||
}
|
||||
|
||||
std::string OwnerUpdater::toString() const
|
||||
@ -193,7 +193,7 @@ std::string OwnerUpdater::toString() const
|
||||
|
||||
JsonNode OwnerUpdater::toJsonNode() const
|
||||
{
|
||||
return JsonUtils::stringNode("BONUS_OWNER_UPDATER");
|
||||
return JsonNode("BONUS_OWNER_UPDATER");
|
||||
}
|
||||
|
||||
std::shared_ptr<Bonus> OwnerUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context) const
|
||||
|
@ -46,7 +46,7 @@ void CampaignHandler::readCampaign(Campaign * ret, const std::vector<ui8> & inpu
|
||||
}
|
||||
else // text format (json)
|
||||
{
|
||||
JsonNode jsonCampaign((const char*)input.data(), input.size());
|
||||
JsonNode jsonCampaign(reinterpret_cast<const std::byte*>(input.data()), input.size());
|
||||
readHeaderFromJson(*ret, jsonCampaign, filename, modName, encoding);
|
||||
|
||||
for(auto & scenario : jsonCampaign["scenarios"].Vector())
|
||||
|
@ -117,7 +117,7 @@ void CFilesystemGenerator::loadJsonMap(const std::string &mountPoint, const Json
|
||||
if (filename)
|
||||
{
|
||||
auto configData = CResourceHandler::get("initial")->load(JsonPath::builtin(URI))->readAll();
|
||||
const JsonNode configInitial(reinterpret_cast<char *>(configData.first.get()), configData.second);
|
||||
const JsonNode configInitial(reinterpret_cast<std::byte *>(configData.first.get()), configData.second);
|
||||
filesystem->addLoader(new CMappedFileLoader(mountPoint, configInitial), false);
|
||||
}
|
||||
}
|
||||
@ -212,7 +212,7 @@ void CResourceHandler::load(const std::string &fsConfigURI, bool extractArchives
|
||||
{
|
||||
auto fsConfigData = get("initial")->load(JsonPath::builtin(fsConfigURI))->readAll();
|
||||
|
||||
const JsonNode fsConfig(reinterpret_cast<char *>(fsConfigData.first.get()), fsConfigData.second);
|
||||
const JsonNode fsConfig(reinterpret_cast<std::byte *>(fsConfigData.first.get()), fsConfigData.second);
|
||||
|
||||
addFilesystem("data", ModScope::scopeBuiltin(), createFileSystem("", fsConfig["filesystem"], extractArchives));
|
||||
}
|
||||
|
@ -13,22 +13,46 @@
|
||||
|
||||
#include "JsonValidator.h"
|
||||
|
||||
#include "../ScopeGuard.h"
|
||||
#include "../CGeneralTextHandler.h"
|
||||
#include "../VCMI_Lib.h"
|
||||
#include "../bonuses/BonusParams.h"
|
||||
#include "../bonuses/Bonus.h"
|
||||
#include "../bonuses/Limiters.h"
|
||||
#include "../bonuses/Propagators.h"
|
||||
#include "../bonuses/Updaters.h"
|
||||
#include "../filesystem/Filesystem.h"
|
||||
#include "../modding/IdentifierStorage.h"
|
||||
#include "../VCMI_Lib.h" //for identifier resolution
|
||||
#include "../CGeneralTextHandler.h"
|
||||
#include "../constants/StringConstants.h"
|
||||
#include "../battle/BattleHex.h"
|
||||
#include "../modding/IdentifierStorage.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
VCMI_LIB_USING_NAMESPACE
|
||||
|
||||
static const JsonNode nullNode;
|
||||
template <typename T>
|
||||
const T parseByMap(const std::map<std::string, T> & map, const JsonNode * val, const std::string & err)
|
||||
{
|
||||
if (!val->isNull())
|
||||
{
|
||||
const std::string & type = val->String();
|
||||
auto it = map.find(type);
|
||||
if (it == map.end())
|
||||
{
|
||||
logMod->error("Error: invalid %s%s.", err, type);
|
||||
return {};
|
||||
}
|
||||
else
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T parseByMapN(const std::map<std::string, T> & map, const JsonNode * val, const std::string & err)
|
||||
{
|
||||
if(val->isNumber())
|
||||
return static_cast<T>(val->Integer());
|
||||
else
|
||||
return parseByMap<T>(map, val, err);
|
||||
}
|
||||
|
||||
static void loadBonusSubtype(BonusSubtypeID & subtype, BonusType type, const JsonNode & node)
|
||||
{
|
||||
@ -40,14 +64,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;
|
||||
}
|
||||
@ -270,6 +294,77 @@ static void loadBonusSourceInstance(BonusSourceID & sourceInstance, BonusSource
|
||||
}
|
||||
}
|
||||
|
||||
static BonusParams convertDeprecatedBonus(const JsonNode &ability)
|
||||
{
|
||||
if(vstd::contains(deprecatedBonusSet, ability["type"].String()))
|
||||
{
|
||||
logMod->warn("There is deprecated bonus found:\n%s\nTrying to convert...", ability.toString());
|
||||
auto params = BonusParams(ability["type"].String(),
|
||||
ability["subtype"].isString() ? ability["subtype"].String() : "",
|
||||
ability["subtype"].isNumber() ? ability["subtype"].Integer() : -1);
|
||||
if(params.isConverted)
|
||||
{
|
||||
if(ability["type"].String() == "SECONDARY_SKILL_PREMY" && bonusValueMap.find(ability["valueType"].String())->second == BonusValueType::PERCENT_TO_BASE) //assume secondary skill special
|
||||
{
|
||||
params.valueType = BonusValueType::PERCENT_TO_TARGET_TYPE;
|
||||
params.targetType = BonusSource::SECONDARY_SKILL;
|
||||
}
|
||||
|
||||
logMod->warn("Please, use this bonus:\n%s\nConverted successfully!", params.toJson().toString());
|
||||
return params;
|
||||
}
|
||||
else
|
||||
logMod->error("Cannot convert bonus!\n%s", ability.toString());
|
||||
}
|
||||
BonusParams ret;
|
||||
ret.isConverted = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static TUpdaterPtr parseUpdater(const JsonNode & updaterJson)
|
||||
{
|
||||
switch(updaterJson.getType())
|
||||
{
|
||||
case JsonNode::JsonType::DATA_STRING:
|
||||
return parseByMap(bonusUpdaterMap, &updaterJson, "updater type ");
|
||||
break;
|
||||
case JsonNode::JsonType::DATA_STRUCT:
|
||||
if(updaterJson["type"].String() == "GROWS_WITH_LEVEL")
|
||||
{
|
||||
auto updater = std::make_shared<GrowsWithLevelUpdater>();
|
||||
const JsonVector param = updaterJson["parameters"].Vector();
|
||||
updater->valPer20 = static_cast<int>(param[0].Integer());
|
||||
if(param.size() > 1)
|
||||
updater->stepSize = static_cast<int>(param[1].Integer());
|
||||
return updater;
|
||||
}
|
||||
else if (updaterJson["type"].String() == "ARMY_MOVEMENT")
|
||||
{
|
||||
auto updater = std::make_shared<ArmyMovementUpdater>();
|
||||
if(updaterJson["parameters"].isVector())
|
||||
{
|
||||
const auto & param = updaterJson["parameters"].Vector();
|
||||
if(param.size() < 4)
|
||||
logMod->warn("Invalid ARMY_MOVEMENT parameters, using default!");
|
||||
else
|
||||
{
|
||||
updater->base = static_cast<si32>(param.at(0).Integer());
|
||||
updater->divider = static_cast<si32>(param.at(1).Integer());
|
||||
updater->multiplier = static_cast<si32>(param.at(2).Integer());
|
||||
updater->max = static_cast<si32>(param.at(3).Integer());
|
||||
}
|
||||
return updater;
|
||||
}
|
||||
}
|
||||
else
|
||||
logMod->warn("Unknown updater type \"%s\"", updaterJson["type"].String());
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonVector & ability_vec)
|
||||
{
|
||||
auto b = std::make_shared<Bonus>();
|
||||
@ -290,36 +385,6 @@ std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonVector & ability_vec)
|
||||
return b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T parseByMap(const std::map<std::string, T> & map, const JsonNode * val, const std::string & err)
|
||||
{
|
||||
if (!val->isNull())
|
||||
{
|
||||
const std::string & type = val->String();
|
||||
auto it = map.find(type);
|
||||
if (it == map.end())
|
||||
{
|
||||
logMod->error("Error: invalid %s%s.", err, type);
|
||||
return {};
|
||||
}
|
||||
else
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T parseByMapN(const std::map<std::string, T> & map, const JsonNode * val, const std::string & err)
|
||||
{
|
||||
if(val->isNumber())
|
||||
return static_cast<T>(val->Integer());
|
||||
else
|
||||
return parseByMap<T>(map, val, err);
|
||||
}
|
||||
|
||||
void JsonUtils::resolveAddInfo(CAddInfo & var, const JsonNode & node)
|
||||
{
|
||||
const JsonNode & value = node["addInfo"];
|
||||
@ -553,7 +618,7 @@ std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonNode &ability)
|
||||
if (!parseBonus(ability, b.get()))
|
||||
{
|
||||
// caller code can not handle this case and presumes that returned bonus is always valid
|
||||
logGlobal->error("Failed to parse bonus! Json config was %S ", ability.toJson());
|
||||
logGlobal->error("Failed to parse bonus! Json config was %S ", ability.toString());
|
||||
b->type = BonusType::NONE;
|
||||
return b;
|
||||
}
|
||||
@ -573,75 +638,6 @@ std::shared_ptr<Bonus> JsonUtils::parseBuildingBonus(const JsonNode & ability, c
|
||||
return b;
|
||||
}
|
||||
|
||||
static BonusParams convertDeprecatedBonus(const JsonNode &ability)
|
||||
{
|
||||
if(vstd::contains(deprecatedBonusSet, ability["type"].String()))
|
||||
{
|
||||
logMod->warn("There is deprecated bonus found:\n%s\nTrying to convert...", ability.toJson());
|
||||
auto params = BonusParams(ability["type"].String(),
|
||||
ability["subtype"].isString() ? ability["subtype"].String() : "",
|
||||
ability["subtype"].isNumber() ? ability["subtype"].Integer() : -1);
|
||||
if(params.isConverted)
|
||||
{
|
||||
if(ability["type"].String() == "SECONDARY_SKILL_PREMY" && bonusValueMap.find(ability["valueType"].String())->second == BonusValueType::PERCENT_TO_BASE) //assume secondary skill special
|
||||
{
|
||||
params.valueType = BonusValueType::PERCENT_TO_TARGET_TYPE;
|
||||
params.targetType = BonusSource::SECONDARY_SKILL;
|
||||
}
|
||||
|
||||
logMod->warn("Please, use this bonus:\n%s\nConverted successfully!", params.toJson().toJson());
|
||||
return params;
|
||||
}
|
||||
else
|
||||
logMod->error("Cannot convert bonus!\n%s", ability.toJson());
|
||||
}
|
||||
BonusParams ret;
|
||||
ret.isConverted = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static TUpdaterPtr parseUpdater(const JsonNode & updaterJson)
|
||||
{
|
||||
switch(updaterJson.getType())
|
||||
{
|
||||
case JsonNode::JsonType::DATA_STRING:
|
||||
return parseByMap(bonusUpdaterMap, &updaterJson, "updater type ");
|
||||
break;
|
||||
case JsonNode::JsonType::DATA_STRUCT:
|
||||
if(updaterJson["type"].String() == "GROWS_WITH_LEVEL")
|
||||
{
|
||||
auto updater = std::make_shared<GrowsWithLevelUpdater>();
|
||||
const JsonVector param = updaterJson["parameters"].Vector();
|
||||
updater->valPer20 = static_cast<int>(param[0].Integer());
|
||||
if(param.size() > 1)
|
||||
updater->stepSize = static_cast<int>(param[1].Integer());
|
||||
return updater;
|
||||
}
|
||||
else if (updaterJson["type"].String() == "ARMY_MOVEMENT")
|
||||
{
|
||||
auto updater = std::make_shared<ArmyMovementUpdater>();
|
||||
if(updaterJson["parameters"].isVector())
|
||||
{
|
||||
const auto & param = updaterJson["parameters"].Vector();
|
||||
if(param.size() < 4)
|
||||
logMod->warn("Invalid ARMY_MOVEMENT parameters, using default!");
|
||||
else
|
||||
{
|
||||
updater->base = static_cast<si32>(param.at(0).Integer());
|
||||
updater->divider = static_cast<si32>(param.at(1).Integer());
|
||||
updater->multiplier = static_cast<si32>(param.at(2).Integer());
|
||||
updater->max = static_cast<si32>(param.at(3).Integer());
|
||||
}
|
||||
return updater;
|
||||
}
|
||||
}
|
||||
else
|
||||
logMod->warn("Unknown updater type \"%s\"", updaterJson["type"].String());
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
|
||||
{
|
||||
const JsonNode * value = nullptr;
|
||||
|
@ -14,15 +14,20 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct Bonus;
|
||||
class ILimiter;
|
||||
class CSelector;
|
||||
class CAddInfo;
|
||||
|
||||
namespace JsonUtils
|
||||
{
|
||||
DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonVector & ability_vec);
|
||||
DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonNode & ability);
|
||||
DLL_LINKAGE std::shared_ptr<Bonus> parseBuildingBonus(const JsonNode & ability, const FactionID & faction, const BuildingID & building, const std::string & description);
|
||||
DLL_LINKAGE bool parseBonus(const JsonNode & ability, Bonus * placement);
|
||||
DLL_LINKAGE std::shared_ptr<ILimiter> parseLimiter(const JsonNode & limiter);
|
||||
DLL_LINKAGE CSelector parseSelector(const JsonNode &ability);
|
||||
DLL_LINKAGE void resolveAddInfo(CAddInfo & var, const JsonNode & node);
|
||||
std::shared_ptr<Bonus> parseBonus(const JsonVector & ability_vec);
|
||||
std::shared_ptr<Bonus> parseBonus(const JsonNode & ability);
|
||||
std::shared_ptr<Bonus> parseBuildingBonus(const JsonNode & ability, const FactionID & faction, const BuildingID & building, const std::string & description);
|
||||
bool parseBonus(const JsonNode & ability, Bonus * placement);
|
||||
std::shared_ptr<ILimiter> parseLimiter(const JsonNode & limiter);
|
||||
CSelector parseSelector(const JsonNode &ability);
|
||||
void resolveAddInfo(CAddInfo & var, const JsonNode & node);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
20
lib/json/JsonFormatException.h
Normal file
20
lib/json/JsonFormatException.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* JsonFormatException.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class DLL_LINKAGE JsonFormatException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
using runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -11,12 +11,10 @@
|
||||
#include "StdInc.h"
|
||||
#include "JsonNode.h"
|
||||
|
||||
#include "filesystem/Filesystem.h"
|
||||
#include "JsonParser.h"
|
||||
#include "JsonWriter.h"
|
||||
#include "filesystem/Filesystem.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
// to avoid duplicating const and non-const code
|
||||
template<typename Node>
|
||||
Node & resolvePointer(Node & in, const std::string & pointer)
|
||||
@ -40,68 +38,96 @@ Node & resolvePointer(Node & in, const std::string & pointer)
|
||||
|
||||
auto index = boost::lexical_cast<size_t>(entry);
|
||||
|
||||
if (in.Vector().size() > index)
|
||||
if(in.Vector().size() > index)
|
||||
return in.Vector()[index].resolvePointer(remainer);
|
||||
}
|
||||
return in[entry].resolvePointer(remainer);
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
using namespace JsonDetail;
|
||||
static const JsonNode nullNode;
|
||||
|
||||
class LibClasses;
|
||||
class CModHandler;
|
||||
|
||||
static const JsonNode nullNode;
|
||||
|
||||
JsonNode::JsonNode(JsonType Type)
|
||||
JsonNode::JsonNode(bool boolean)
|
||||
: data(boolean)
|
||||
{
|
||||
setType(Type);
|
||||
}
|
||||
|
||||
JsonNode::JsonNode(const std::byte *data, size_t datasize)
|
||||
:JsonNode(reinterpret_cast<const char*>(data), datasize)
|
||||
{}
|
||||
|
||||
JsonNode::JsonNode(const char *data, size_t datasize)
|
||||
JsonNode::JsonNode(int32_t number)
|
||||
: data(static_cast<int64_t>(number))
|
||||
{
|
||||
JsonParser parser(data, datasize);
|
||||
}
|
||||
|
||||
JsonNode::JsonNode(uint32_t number)
|
||||
: data(static_cast<int64_t>(number))
|
||||
{
|
||||
}
|
||||
|
||||
JsonNode::JsonNode(int64_t number)
|
||||
: data(number)
|
||||
{
|
||||
}
|
||||
|
||||
JsonNode::JsonNode(double number)
|
||||
: data(number)
|
||||
{
|
||||
}
|
||||
|
||||
JsonNode::JsonNode(const std::string & string)
|
||||
: data(string)
|
||||
{
|
||||
}
|
||||
|
||||
JsonNode::JsonNode(const std::byte * data, size_t datasize)
|
||||
: JsonNode(data, datasize, JsonParsingSettings())
|
||||
{
|
||||
}
|
||||
|
||||
JsonNode::JsonNode(const std::byte * data, size_t datasize, const JsonParsingSettings & parserSettings)
|
||||
{
|
||||
JsonParser parser(data, datasize, parserSettings);
|
||||
*this = parser.parse("<unknown>");
|
||||
}
|
||||
|
||||
JsonNode::JsonNode(const JsonPath & fileURI)
|
||||
:JsonNode(fileURI, JsonParsingSettings())
|
||||
{
|
||||
}
|
||||
|
||||
JsonNode::JsonNode(const JsonPath & fileURI, const JsonParsingSettings & parserSettings)
|
||||
{
|
||||
auto file = CResourceHandler::get()->load(fileURI)->readAll();
|
||||
|
||||
JsonParser parser(reinterpret_cast<char*>(file.first.get()), file.second);
|
||||
JsonParser parser(reinterpret_cast<std::byte *>(file.first.get()), file.second, parserSettings);
|
||||
*this = parser.parse(fileURI.getName());
|
||||
}
|
||||
|
||||
JsonNode::JsonNode(const std::string & idx, const JsonPath & fileURI)
|
||||
JsonNode::JsonNode(const JsonPath & fileURI, const std::string & idx)
|
||||
{
|
||||
auto file = CResourceHandler::get(idx)->load(fileURI)->readAll();
|
||||
|
||||
JsonParser parser(reinterpret_cast<char*>(file.first.get()), file.second);
|
||||
|
||||
JsonParser parser(reinterpret_cast<std::byte *>(file.first.get()), file.second, JsonParsingSettings());
|
||||
*this = parser.parse(fileURI.getName());
|
||||
}
|
||||
|
||||
JsonNode::JsonNode(const JsonPath & fileURI, bool &isValidSyntax)
|
||||
JsonNode::JsonNode(const JsonPath & fileURI, bool & isValidSyntax)
|
||||
{
|
||||
auto file = CResourceHandler::get()->load(fileURI)->readAll();
|
||||
|
||||
JsonParser parser(reinterpret_cast<char*>(file.first.get()), file.second);
|
||||
JsonParser parser(reinterpret_cast<std::byte *>(file.first.get()), file.second, JsonParsingSettings());
|
||||
*this = parser.parse(fileURI.getName());
|
||||
isValidSyntax = parser.isValid();
|
||||
}
|
||||
|
||||
bool JsonNode::operator == (const JsonNode &other) const
|
||||
bool JsonNode::operator==(const JsonNode & other) const
|
||||
{
|
||||
return data == other.data;
|
||||
}
|
||||
|
||||
bool JsonNode::operator != (const JsonNode &other) const
|
||||
bool JsonNode::operator!=(const JsonNode & other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
@ -111,25 +137,42 @@ 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;
|
||||
if (recursive)
|
||||
return modScope;
|
||||
}
|
||||
|
||||
void JsonNode::setOverrideFlag(bool value)
|
||||
{
|
||||
overrideFlag = value;
|
||||
}
|
||||
|
||||
bool JsonNode::getOverrideFlag() const
|
||||
{
|
||||
return overrideFlag;
|
||||
}
|
||||
|
||||
void JsonNode::setModScope(const std::string & metadata, bool recursive)
|
||||
{
|
||||
modScope = metadata;
|
||||
if(recursive)
|
||||
{
|
||||
switch (getType())
|
||||
switch(getType())
|
||||
{
|
||||
break; case JsonType::DATA_VECTOR:
|
||||
break;
|
||||
case JsonType::DATA_VECTOR:
|
||||
{
|
||||
for(auto & node : Vector())
|
||||
{
|
||||
node.setMeta(metadata);
|
||||
node.setModScope(metadata);
|
||||
}
|
||||
}
|
||||
break; case JsonType::DATA_STRUCT:
|
||||
break;
|
||||
case JsonType::DATA_STRUCT:
|
||||
{
|
||||
for(auto & node : Struct())
|
||||
{
|
||||
node.second.setMeta(metadata);
|
||||
node.second.setModScope(metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -138,7 +181,7 @@ void JsonNode::setMeta(const std::string & metadata, bool recursive)
|
||||
|
||||
void JsonNode::setType(JsonType Type)
|
||||
{
|
||||
if (getType() == Type)
|
||||
if(getType() == Type)
|
||||
return;
|
||||
|
||||
//float<->int conversion
|
||||
@ -158,13 +201,27 @@ void JsonNode::setType(JsonType Type)
|
||||
//Set new node type
|
||||
switch(Type)
|
||||
{
|
||||
break; case JsonType::DATA_NULL: data = JsonData();
|
||||
break; case JsonType::DATA_BOOL: data = JsonData(false);
|
||||
break; case JsonType::DATA_FLOAT: data = JsonData(static_cast<double>(0.0));
|
||||
break; case JsonType::DATA_STRING: data = JsonData(std::string());
|
||||
break; case JsonType::DATA_VECTOR: data = JsonData(JsonVector());
|
||||
break; case JsonType::DATA_STRUCT: data = JsonData(JsonMap());
|
||||
break; case JsonType::DATA_INTEGER: data = JsonData(static_cast<si64>(0));
|
||||
case JsonType::DATA_NULL:
|
||||
data = JsonData();
|
||||
break;
|
||||
case JsonType::DATA_BOOL:
|
||||
data = JsonData(false);
|
||||
break;
|
||||
case JsonType::DATA_FLOAT:
|
||||
data = JsonData(0.0);
|
||||
break;
|
||||
case JsonType::DATA_STRING:
|
||||
data = JsonData(std::string());
|
||||
break;
|
||||
case JsonType::DATA_VECTOR:
|
||||
data = JsonData(JsonVector());
|
||||
break;
|
||||
case JsonType::DATA_STRUCT:
|
||||
data = JsonData(JsonMap());
|
||||
break;
|
||||
case JsonType::DATA_INTEGER:
|
||||
data = JsonData(static_cast<si64>(0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,18 +254,18 @@ bool JsonNode::containsBaseData() const
|
||||
{
|
||||
switch(getType())
|
||||
{
|
||||
case JsonType::DATA_NULL:
|
||||
return false;
|
||||
case JsonType::DATA_STRUCT:
|
||||
for(const auto & elem : Struct())
|
||||
{
|
||||
if(elem.second.containsBaseData())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
//other types (including vector) cannot be extended via merge
|
||||
return true;
|
||||
case JsonType::DATA_NULL:
|
||||
return false;
|
||||
case JsonType::DATA_STRUCT:
|
||||
for(const auto & elem : Struct())
|
||||
{
|
||||
if(elem.second.containsBaseData())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
//other types (including vector) cannot be extended via merge
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,14 +273,14 @@ bool JsonNode::isCompact() const
|
||||
{
|
||||
switch(getType())
|
||||
{
|
||||
case JsonType::DATA_VECTOR:
|
||||
for(const JsonNode & elem : Vector())
|
||||
{
|
||||
if(!elem.isCompact())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case JsonType::DATA_STRUCT:
|
||||
case JsonType::DATA_VECTOR:
|
||||
for(const JsonNode & elem : Vector())
|
||||
{
|
||||
if(!elem.isCompact())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case JsonType::DATA_STRUCT:
|
||||
{
|
||||
auto propertyCount = Struct().size();
|
||||
if(propertyCount == 0)
|
||||
@ -231,9 +288,9 @@ bool JsonNode::isCompact() const
|
||||
else if(propertyCount == 1)
|
||||
return Struct().begin()->second.isCompact();
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,7 +310,7 @@ bool JsonNode::TryBoolFromString(bool & success) const
|
||||
|
||||
if(success)
|
||||
return true;
|
||||
|
||||
|
||||
success = boolParamStr == "false";
|
||||
}
|
||||
return false;
|
||||
@ -300,20 +357,22 @@ JsonMap & JsonNode::Struct()
|
||||
return std::get<JsonMap>(data);
|
||||
}
|
||||
|
||||
const bool boolDefault = false;
|
||||
bool JsonNode::Bool() const
|
||||
{
|
||||
static const bool boolDefault = false;
|
||||
|
||||
assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_BOOL);
|
||||
|
||||
if (getType() == JsonType::DATA_BOOL)
|
||||
if(getType() == JsonType::DATA_BOOL)
|
||||
return std::get<bool>(data);
|
||||
|
||||
return boolDefault;
|
||||
}
|
||||
|
||||
const double floatDefault = 0;
|
||||
double JsonNode::Float() const
|
||||
{
|
||||
static const double floatDefault = 0;
|
||||
|
||||
assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_INTEGER || getType() == JsonType::DATA_FLOAT);
|
||||
|
||||
if(getType() == JsonType::DATA_FLOAT)
|
||||
@ -325,9 +384,10 @@ double JsonNode::Float() const
|
||||
return floatDefault;
|
||||
}
|
||||
|
||||
const si64 integerDefault = 0;
|
||||
si64 JsonNode::Integer() const
|
||||
{
|
||||
static const si64 integerDefault = 0;
|
||||
|
||||
assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_INTEGER || getType() == JsonType::DATA_FLOAT);
|
||||
|
||||
if(getType() == JsonType::DATA_INTEGER)
|
||||
@ -339,34 +399,37 @@ si64 JsonNode::Integer() const
|
||||
return integerDefault;
|
||||
}
|
||||
|
||||
const std::string stringDefault = std::string();
|
||||
const std::string & JsonNode::String() const
|
||||
{
|
||||
static const std::string stringDefault;
|
||||
|
||||
assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_STRING);
|
||||
|
||||
if (getType() == JsonType::DATA_STRING)
|
||||
if(getType() == JsonType::DATA_STRING)
|
||||
return std::get<std::string>(data);
|
||||
|
||||
return stringDefault;
|
||||
}
|
||||
|
||||
const JsonVector vectorDefault = JsonVector();
|
||||
const JsonVector & JsonNode::Vector() const
|
||||
{
|
||||
static const JsonVector vectorDefault;
|
||||
|
||||
assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_VECTOR);
|
||||
|
||||
if (getType() == JsonType::DATA_VECTOR)
|
||||
if(getType() == JsonType::DATA_VECTOR)
|
||||
return std::get<JsonVector>(data);
|
||||
|
||||
return vectorDefault;
|
||||
}
|
||||
|
||||
const JsonMap mapDefault = JsonMap();
|
||||
const JsonMap & JsonNode::Struct() const
|
||||
{
|
||||
static const JsonMap mapDefault;
|
||||
|
||||
assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_STRUCT);
|
||||
|
||||
if (getType() == JsonType::DATA_STRUCT)
|
||||
if(getType() == JsonType::DATA_STRUCT)
|
||||
return std::get<JsonMap>(data);
|
||||
|
||||
return mapDefault;
|
||||
@ -380,49 +443,57 @@ JsonNode & JsonNode::operator[](const std::string & child)
|
||||
const JsonNode & JsonNode::operator[](const std::string & child) const
|
||||
{
|
||||
auto it = Struct().find(child);
|
||||
if (it != Struct().end())
|
||||
if(it != Struct().end())
|
||||
return it->second;
|
||||
return nullNode;
|
||||
}
|
||||
|
||||
JsonNode & JsonNode::operator[](size_t child)
|
||||
{
|
||||
if (child >= Vector().size() )
|
||||
if(child >= Vector().size())
|
||||
Vector().resize(child + 1);
|
||||
return Vector()[child];
|
||||
}
|
||||
|
||||
const JsonNode & JsonNode::operator[](size_t child) const
|
||||
{
|
||||
if (child < Vector().size() )
|
||||
if(child < Vector().size())
|
||||
return Vector()[child];
|
||||
|
||||
return nullNode;
|
||||
}
|
||||
|
||||
const JsonNode & JsonNode::resolvePointer(const std::string &jsonPointer) const
|
||||
const JsonNode & JsonNode::resolvePointer(const std::string & jsonPointer) const
|
||||
{
|
||||
return ::resolvePointer(*this, jsonPointer);
|
||||
}
|
||||
|
||||
JsonNode & JsonNode::resolvePointer(const std::string &jsonPointer)
|
||||
JsonNode & JsonNode::resolvePointer(const std::string & jsonPointer)
|
||||
{
|
||||
return ::resolvePointer(*this, jsonPointer);
|
||||
}
|
||||
|
||||
std::vector<std::byte> JsonNode::toBytes(bool compact) const
|
||||
std::vector<std::byte> JsonNode::toBytes() const
|
||||
{
|
||||
std::string jsonString = toJson(compact);
|
||||
auto dataBegin = reinterpret_cast<const std::byte*>(jsonString.data());
|
||||
std::string jsonString = toString();
|
||||
auto dataBegin = reinterpret_cast<const std::byte *>(jsonString.data());
|
||||
auto dataEnd = dataBegin + jsonString.size();
|
||||
std::vector<std::byte> result(dataBegin, dataEnd);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string JsonNode::toJson(bool compact) const
|
||||
std::string JsonNode::toCompactString() const
|
||||
{
|
||||
std::ostringstream out;
|
||||
JsonWriter writer(out, compact);
|
||||
JsonWriter writer(out, true);
|
||||
writer.writeNode(*this);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
std::string JsonNode::toString() const
|
||||
{
|
||||
std::ostringstream out;
|
||||
JsonWriter writer(out, false);
|
||||
writer.writeNode(*this);
|
||||
return out.str();
|
||||
}
|
||||
|
@ -17,10 +17,23 @@ class JsonNode;
|
||||
using JsonMap = std::map<std::string, JsonNode>;
|
||||
using JsonVector = std::vector<JsonNode>;
|
||||
|
||||
struct Bonus;
|
||||
class CSelector;
|
||||
class CAddInfo;
|
||||
class ILimiter;
|
||||
struct DLL_LINKAGE JsonParsingSettings
|
||||
{
|
||||
enum class JsonFormatMode
|
||||
{
|
||||
JSON, // strict implementation of json format
|
||||
JSONC, // json format that also allows comments that start from '//'
|
||||
JSON5 // Partial support of 'json5' format
|
||||
};
|
||||
|
||||
JsonFormatMode mode = JsonFormatMode::JSON5;
|
||||
|
||||
/// Maximum depth of elements
|
||||
uint32_t maxDepth = 30;
|
||||
|
||||
/// If set to true, parser will throw on any encountered error
|
||||
bool strict = false;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE JsonNode
|
||||
{
|
||||
@ -37,30 +50,44 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
using JsonData = std::variant<std::monostate, bool, double, std::string, JsonVector, JsonMap, si64>;
|
||||
using JsonData = std::variant<std::monostate, bool, double, std::string, JsonVector, JsonMap, int64_t>;
|
||||
|
||||
JsonData data;
|
||||
|
||||
public:
|
||||
/// free to use metadata fields
|
||||
std::string meta;
|
||||
// meta-flags like override
|
||||
std::vector<std::string> flags;
|
||||
/// Mod-origin of this particular field
|
||||
std::string modScope;
|
||||
|
||||
//Create empty node
|
||||
JsonNode(JsonType Type = JsonType::DATA_NULL);
|
||||
//Create tree from Json-formatted input
|
||||
explicit JsonNode(const char * data, size_t datasize);
|
||||
bool overrideFlag = false;
|
||||
|
||||
public:
|
||||
JsonNode() = default;
|
||||
|
||||
/// Create single node with specified value
|
||||
explicit JsonNode(bool boolean);
|
||||
explicit JsonNode(int32_t number);
|
||||
explicit JsonNode(uint32_t number);
|
||||
explicit JsonNode(int64_t number);
|
||||
explicit JsonNode(double number);
|
||||
explicit JsonNode(const std::string & string);
|
||||
|
||||
/// Create tree from Json-formatted input
|
||||
explicit JsonNode(const std::byte * data, size_t datasize);
|
||||
//Create tree from JSON file
|
||||
explicit JsonNode(const std::byte * data, size_t datasize, const JsonParsingSettings & parserSettings);
|
||||
|
||||
/// Create tree from JSON file
|
||||
explicit JsonNode(const JsonPath & fileURI);
|
||||
explicit JsonNode(const std::string & modName, const JsonPath & fileURI);
|
||||
explicit JsonNode(const JsonPath & fileURI, const JsonParsingSettings & parserSettings);
|
||||
explicit JsonNode(const JsonPath & fileURI, const std::string & modName);
|
||||
explicit JsonNode(const JsonPath & fileURI, bool & isValidSyntax);
|
||||
|
||||
bool operator == (const JsonNode &other) const;
|
||||
bool operator != (const JsonNode &other) const;
|
||||
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);
|
||||
|
||||
void setOverrideFlag(bool value);
|
||||
bool getOverrideFlag() const;
|
||||
|
||||
/// Convert node to another type. Converting to nullptr will clear all data
|
||||
void setType(JsonType Type);
|
||||
@ -114,121 +141,91 @@ public:
|
||||
const JsonNode & operator[](const std::string & child) const;
|
||||
|
||||
JsonNode & operator[](size_t child);
|
||||
const JsonNode & operator[](size_t child) const;
|
||||
const JsonNode & operator[](size_t child) const;
|
||||
|
||||
std::string toJson(bool compact = false) const;
|
||||
std::vector<std::byte> toBytes(bool compact = false) const;
|
||||
std::string toCompactString() const;
|
||||
std::string toString() const;
|
||||
std::vector<std::byte> toBytes() const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h)
|
||||
template<typename Handler>
|
||||
void serialize(Handler & h)
|
||||
{
|
||||
h & meta;
|
||||
h & flags;
|
||||
h & modScope;
|
||||
|
||||
if(h.version >= Handler::Version::JSON_FLAGS)
|
||||
{
|
||||
h & overrideFlag;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::string> oldFlags;
|
||||
h & oldFlags;
|
||||
}
|
||||
h & data;
|
||||
}
|
||||
};
|
||||
|
||||
namespace JsonDetail
|
||||
{
|
||||
// conversion helpers for JsonNode::convertTo (partial template function instantiation is illegal in c++)
|
||||
|
||||
template <typename T, int arithm>
|
||||
struct JsonConvImpl;
|
||||
inline void convert(bool & value, const JsonNode & node)
|
||||
{
|
||||
value = node.Bool();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct JsonConvImpl<T, 1>
|
||||
template<typename T>
|
||||
auto convert(T & value, const JsonNode & node) -> std::enable_if_t<std::is_integral_v<T>>
|
||||
{
|
||||
value = node.Integer();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto convert(T & value, const JsonNode & node) -> std::enable_if_t<std::is_floating_point_v<T>>
|
||||
{
|
||||
value = node.Float();
|
||||
}
|
||||
|
||||
inline void convert(std::string & value, const JsonNode & node)
|
||||
{
|
||||
value = node.String();
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
void convert(std::map<std::string, Type> & value, const JsonNode & node)
|
||||
{
|
||||
value.clear();
|
||||
for(const JsonMap::value_type & entry : node.Struct())
|
||||
value.insert(entry.first, entry.second.convertTo<Type>());
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
void convert(std::set<Type> & value, const JsonNode & node)
|
||||
{
|
||||
value.clear();
|
||||
for(const JsonVector::value_type & entry : node.Vector())
|
||||
{
|
||||
static T convertImpl(const JsonNode & node)
|
||||
{
|
||||
return T((int)node.Float());
|
||||
}
|
||||
};
|
||||
value.insert(entry.convertTo<Type>());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct JsonConvImpl<T, 0>
|
||||
template<typename Type>
|
||||
void convert(std::vector<Type> & value, const JsonNode & node)
|
||||
{
|
||||
value.clear();
|
||||
for(const JsonVector::value_type & entry : node.Vector())
|
||||
{
|
||||
static T convertImpl(const JsonNode & node)
|
||||
{
|
||||
return T(node.Float());
|
||||
}
|
||||
};
|
||||
value.push_back(entry.convertTo<Type>());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
struct JsonConverter
|
||||
{
|
||||
static Type convert(const JsonNode & node)
|
||||
{
|
||||
///this should be triggered only for numeric types and enums
|
||||
static_assert(std::is_arithmetic_v<Type> || std::is_enum_v<Type> || std::is_class_v<Type>, "Unsupported type for JsonNode::convertTo()!");
|
||||
return JsonConvImpl<Type, std::is_enum_v<Type> || std::is_class_v<Type> >::convertImpl(node);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct JsonConverter<std::map<std::string, Type> >
|
||||
{
|
||||
static std::map<std::string, Type> convert(const JsonNode & node)
|
||||
{
|
||||
std::map<std::string, Type> ret;
|
||||
for (const JsonMap::value_type & entry : node.Struct())
|
||||
{
|
||||
ret.insert(entry.first, entry.second.convertTo<Type>());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct JsonConverter<std::set<Type> >
|
||||
{
|
||||
static std::set<Type> convert(const JsonNode & node)
|
||||
{
|
||||
std::set<Type> ret;
|
||||
for(const JsonVector::value_type & entry : node.Vector())
|
||||
{
|
||||
ret.insert(entry.convertTo<Type>());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct JsonConverter<std::vector<Type> >
|
||||
{
|
||||
static std::vector<Type> convert(const JsonNode & node)
|
||||
{
|
||||
std::vector<Type> ret;
|
||||
for (const JsonVector::value_type & entry: node.Vector())
|
||||
{
|
||||
ret.push_back(entry.convertTo<Type>());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct JsonConverter<std::string>
|
||||
{
|
||||
static std::string convert(const JsonNode & node)
|
||||
{
|
||||
return node.String();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct JsonConverter<bool>
|
||||
{
|
||||
static bool convert(const JsonNode & node)
|
||||
{
|
||||
return node.Bool();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
Type JsonNode::convertTo() const
|
||||
{
|
||||
return JsonDetail::JsonConverter<Type>::convert(*this);
|
||||
Type result;
|
||||
JsonDetail::convert(result, *this);
|
||||
return result;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -11,15 +11,19 @@
|
||||
#include "StdInc.h"
|
||||
#include "JsonParser.h"
|
||||
|
||||
#include "../ScopeGuard.h"
|
||||
#include "../TextOperations.h"
|
||||
#include "JsonFormatException.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
JsonParser::JsonParser(const char * inputString, size_t stringSize):
|
||||
input(inputString, stringSize),
|
||||
lineCount(1),
|
||||
lineStart(0),
|
||||
pos(0)
|
||||
JsonParser::JsonParser(const std::byte * inputString, size_t stringSize, const JsonParsingSettings & settings)
|
||||
: settings(settings)
|
||||
, input(reinterpret_cast<const char *>(inputString), stringSize)
|
||||
, lineCount(1)
|
||||
, currentDepth(0)
|
||||
, lineStart(0)
|
||||
, pos(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -27,24 +31,29 @@ JsonNode JsonParser::parse(const std::string & fileName)
|
||||
{
|
||||
JsonNode root;
|
||||
|
||||
if (input.size() == 0)
|
||||
if(input.empty())
|
||||
{
|
||||
error("File is empty", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!TextOperations::isValidUnicodeString(&input[0], input.size()))
|
||||
if(!TextOperations::isValidUnicodeString(input.data(), input.size()))
|
||||
error("Not a valid UTF-8 file", false);
|
||||
|
||||
// If file starts with BOM - skip it
|
||||
uint32_t firstCharacter = TextOperations::getUnicodeCodepoint(input.data(), input.size());
|
||||
if (firstCharacter == 0xFEFF)
|
||||
pos += TextOperations::getUnicodeCharacterSize(input[0]);
|
||||
|
||||
extractValue(root);
|
||||
extractWhitespace(false);
|
||||
|
||||
//Warn if there are any non-whitespace symbols left
|
||||
if (pos < input.size())
|
||||
if(pos < input.size())
|
||||
error("Not all file was parsed!", true);
|
||||
}
|
||||
|
||||
if (!errors.empty())
|
||||
if(!errors.empty())
|
||||
{
|
||||
logMod->warn("File %s is not a valid JSON file!", fileName);
|
||||
logMod->warn(errors);
|
||||
@ -59,33 +68,43 @@ bool JsonParser::isValid()
|
||||
|
||||
bool JsonParser::extractSeparator()
|
||||
{
|
||||
if (!extractWhitespace())
|
||||
if(!extractWhitespace())
|
||||
return false;
|
||||
|
||||
if ( input[pos] !=':')
|
||||
if(input[pos] != ':')
|
||||
return error("Separator expected");
|
||||
|
||||
pos++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::extractValue(JsonNode &node)
|
||||
bool JsonParser::extractValue(JsonNode & node)
|
||||
{
|
||||
if (!extractWhitespace())
|
||||
if(!extractWhitespace())
|
||||
return false;
|
||||
|
||||
switch (input[pos])
|
||||
switch(input[pos])
|
||||
{
|
||||
case '\"': return extractString(node);
|
||||
case 'n' : return extractNull(node);
|
||||
case 't' : return extractTrue(node);
|
||||
case 'f' : return extractFalse(node);
|
||||
case '{' : return extractStruct(node);
|
||||
case '[' : return extractArray(node);
|
||||
case '-' : return extractFloat(node);
|
||||
case '\"':
|
||||
case '\'':
|
||||
return extractString(node);
|
||||
case 'n':
|
||||
return extractNull(node);
|
||||
case 't':
|
||||
return extractTrue(node);
|
||||
case 'f':
|
||||
return extractFalse(node);
|
||||
case '{':
|
||||
return extractStruct(node);
|
||||
case '[':
|
||||
return extractArray(node);
|
||||
case '-':
|
||||
case '+':
|
||||
case '.':
|
||||
return extractFloat(node);
|
||||
default:
|
||||
{
|
||||
if (input[pos] >= '0' && input[pos] <= '9')
|
||||
if(input[pos] >= '0' && input[pos] <= '9')
|
||||
return extractFloat(node);
|
||||
return error("Value expected!");
|
||||
}
|
||||
@ -94,88 +113,127 @@ bool JsonParser::extractValue(JsonNode &node)
|
||||
|
||||
bool JsonParser::extractWhitespace(bool verbose)
|
||||
{
|
||||
while (true)
|
||||
//TODO: JSON5 - C-style multi-line comments
|
||||
//TODO: JSON5 - Additional white space characters are allowed
|
||||
|
||||
while(true)
|
||||
{
|
||||
while(pos < input.size() && static_cast<ui8>(input[pos]) <= ' ')
|
||||
{
|
||||
if (input[pos] == '\n')
|
||||
if(input[pos] == '\n')
|
||||
{
|
||||
lineCount++;
|
||||
lineStart = pos+1;
|
||||
lineStart = pos + 1;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
if (pos >= input.size() || input[pos] != '/')
|
||||
|
||||
if(pos >= input.size() || input[pos] != '/')
|
||||
break;
|
||||
|
||||
if(settings.mode == JsonParsingSettings::JsonFormatMode::JSON)
|
||||
error("Comments are not permitted in json!", true);
|
||||
|
||||
pos++;
|
||||
if (pos == input.size())
|
||||
if(pos == input.size())
|
||||
break;
|
||||
if (input[pos] == '/')
|
||||
if(input[pos] == '/')
|
||||
pos++;
|
||||
else
|
||||
error("Comments must consist of two slashes!", true);
|
||||
|
||||
while (pos < input.size() && input[pos] != '\n')
|
||||
while(pos < input.size() && input[pos] != '\n')
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (pos >= input.size() && verbose)
|
||||
if(pos >= input.size() && verbose)
|
||||
return error("Unexpected end of file!");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::extractEscaping(std::string &str)
|
||||
bool JsonParser::extractEscaping(std::string & str)
|
||||
{
|
||||
// TODO: support unicode escaping:
|
||||
// \u1234
|
||||
|
||||
switch(input[pos])
|
||||
{
|
||||
break; case '\"': str += '\"';
|
||||
break; case '\\': str += '\\';
|
||||
break; case 'b': str += '\b';
|
||||
break; case 'f': str += '\f';
|
||||
break; case 'n': str += '\n';
|
||||
break; case 'r': str += '\r';
|
||||
break; case 't': str += '\t';
|
||||
break; case '/': str += '/';
|
||||
break; default: return error("Unknown escape sequence!", true);
|
||||
case '\"':
|
||||
str += '\"';
|
||||
break;
|
||||
case '\\':
|
||||
str += '\\';
|
||||
break;
|
||||
case 'b':
|
||||
str += '\b';
|
||||
break;
|
||||
case 'f':
|
||||
str += '\f';
|
||||
break;
|
||||
case 'n':
|
||||
str += '\n';
|
||||
break;
|
||||
case 'r':
|
||||
str += '\r';
|
||||
break;
|
||||
case 't':
|
||||
str += '\t';
|
||||
break;
|
||||
case '/':
|
||||
str += '/';
|
||||
break;
|
||||
default:
|
||||
return error("Unknown escape sequence!", true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::extractString(std::string &str)
|
||||
bool JsonParser::extractString(std::string & str)
|
||||
{
|
||||
if (input[pos] != '\"')
|
||||
return error("String expected!");
|
||||
//TODO: JSON5 - line breaks escaping
|
||||
|
||||
if(settings.mode < JsonParsingSettings::JsonFormatMode::JSON5)
|
||||
{
|
||||
if(input[pos] != '\"')
|
||||
return error("String expected!");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(input[pos] != '\"' && input[pos] != '\'')
|
||||
return error("String expected!");
|
||||
}
|
||||
|
||||
char lineTerminator = input[pos];
|
||||
pos++;
|
||||
|
||||
size_t first = pos;
|
||||
|
||||
while (pos != input.size())
|
||||
while(pos != input.size())
|
||||
{
|
||||
if (input[pos] == '\"') // Correct end of string
|
||||
if(input[pos] == lineTerminator) // Correct end of string
|
||||
{
|
||||
str.append( &input[first], pos-first);
|
||||
str.append(&input[first], pos - first);
|
||||
pos++;
|
||||
return true;
|
||||
}
|
||||
if (input[pos] == '\\') // Escaping
|
||||
if(input[pos] == '\\') // Escaping
|
||||
{
|
||||
str.append( &input[first], pos-first);
|
||||
str.append(&input[first], pos - first);
|
||||
pos++;
|
||||
if (pos == input.size())
|
||||
if(pos == input.size())
|
||||
break;
|
||||
extractEscaping(str);
|
||||
first = pos + 1;
|
||||
}
|
||||
if (input[pos] == '\n') // end-of-line
|
||||
if(input[pos] == '\n') // end-of-line
|
||||
{
|
||||
str.append( &input[first], pos-first);
|
||||
str.append(&input[first], pos - first);
|
||||
return error("Closing quote not found!", true);
|
||||
}
|
||||
if(static_cast<unsigned char>(input[pos]) < ' ') // control character
|
||||
{
|
||||
str.append( &input[first], pos-first);
|
||||
first = pos+1;
|
||||
str.append(&input[first], pos - first);
|
||||
first = pos + 1;
|
||||
error("Illegal character in the string!", true);
|
||||
}
|
||||
pos++;
|
||||
@ -183,10 +241,10 @@ bool JsonParser::extractString(std::string &str)
|
||||
return error("Unterminated string!");
|
||||
}
|
||||
|
||||
bool JsonParser::extractString(JsonNode &node)
|
||||
bool JsonParser::extractString(JsonNode & node)
|
||||
{
|
||||
std::string str;
|
||||
if (!extractString(str))
|
||||
if(!extractString(str))
|
||||
return false;
|
||||
|
||||
node.setType(JsonNode::JsonType::DATA_STRING);
|
||||
@ -194,97 +252,146 @@ bool JsonParser::extractString(JsonNode &node)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::extractLiteral(const std::string &literal)
|
||||
bool JsonParser::extractLiteral(std::string & literal)
|
||||
{
|
||||
if (literal.compare(0, literal.size(), &input[pos], literal.size()) != 0)
|
||||
while(pos < input.size())
|
||||
{
|
||||
while (pos < input.size() && ((input[pos]>'a' && input[pos]<'z')
|
||||
|| (input[pos]>'A' && input[pos]<'Z')))
|
||||
pos++;
|
||||
return error("Unknown literal found", true);
|
||||
bool isUpperCase = input[pos] >= 'A' && input[pos] <= 'Z';
|
||||
bool isLowerCase = input[pos] >= 'a' && input[pos] <= 'z';
|
||||
bool isNumber = input[pos] >= '0' && input[pos] <= '9';
|
||||
|
||||
if(!isUpperCase && !isLowerCase && !isNumber)
|
||||
break;
|
||||
|
||||
literal += input[pos];
|
||||
pos++;
|
||||
}
|
||||
|
||||
pos += literal.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::extractNull(JsonNode &node)
|
||||
bool JsonParser::extractAndCompareLiteral(const std::string & expectedLiteral)
|
||||
{
|
||||
if (!extractLiteral("null"))
|
||||
std::string literal;
|
||||
if(!extractLiteral(literal))
|
||||
return false;
|
||||
|
||||
if(literal != expectedLiteral)
|
||||
{
|
||||
return error("Expected " + expectedLiteral + ", but unknown literal found", true);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::extractNull(JsonNode & node)
|
||||
{
|
||||
if(!extractAndCompareLiteral("null"))
|
||||
return false;
|
||||
|
||||
node.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::extractTrue(JsonNode &node)
|
||||
bool JsonParser::extractTrue(JsonNode & node)
|
||||
{
|
||||
if (!extractLiteral("true"))
|
||||
if(!extractAndCompareLiteral("true"))
|
||||
return false;
|
||||
|
||||
node.Bool() = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::extractFalse(JsonNode &node)
|
||||
bool JsonParser::extractFalse(JsonNode & node)
|
||||
{
|
||||
if (!extractLiteral("false"))
|
||||
if(!extractAndCompareLiteral("false"))
|
||||
return false;
|
||||
|
||||
node.Bool() = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::extractStruct(JsonNode &node)
|
||||
bool JsonParser::extractStruct(JsonNode & node)
|
||||
{
|
||||
node.setType(JsonNode::JsonType::DATA_STRUCT);
|
||||
pos++;
|
||||
|
||||
if (!extractWhitespace())
|
||||
if(currentDepth > settings.maxDepth)
|
||||
error("Maximum allowed depth of json structure has been reached", true);
|
||||
|
||||
pos++;
|
||||
currentDepth++;
|
||||
auto guard = vstd::makeScopeGuard([this]()
|
||||
{
|
||||
currentDepth--;
|
||||
});
|
||||
|
||||
if(!extractWhitespace())
|
||||
return false;
|
||||
|
||||
//Empty struct found
|
||||
if (input[pos] == '}')
|
||||
if(input[pos] == '}')
|
||||
{
|
||||
pos++;
|
||||
return true;
|
||||
}
|
||||
|
||||
while (true)
|
||||
while(true)
|
||||
{
|
||||
if (!extractWhitespace())
|
||||
if(!extractWhitespace())
|
||||
return false;
|
||||
|
||||
bool overrideFlag = false;
|
||||
std::string key;
|
||||
if (!extractString(key))
|
||||
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(settings.mode < JsonParsingSettings::JsonFormatMode::JSON5)
|
||||
{
|
||||
if(!vstd::contains(knownFlags, keyAndFlags[i]))
|
||||
error("Encountered unknown flag #" + keyAndFlags[i], true);
|
||||
if(!extractString(key))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(input[pos] == '\'' || input[pos] == '\"')
|
||||
{
|
||||
if(!extractString(key))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!extractLiteral(key))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.Struct().find(key) != node.Struct().end())
|
||||
if(key.find('#') != std::string::npos)
|
||||
{
|
||||
// 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];
|
||||
|
||||
for(int i = 1; i < keyAndFlags.size(); i++)
|
||||
{
|
||||
if(keyAndFlags[i] == "override")
|
||||
overrideFlag = true;
|
||||
else
|
||||
error("Encountered unknown flag #" + keyAndFlags[i], true);
|
||||
}
|
||||
}
|
||||
|
||||
if(node.Struct().find(key) != node.Struct().end())
|
||||
error("Duplicate element encountered!", true);
|
||||
|
||||
if (!extractSeparator())
|
||||
if(!extractSeparator())
|
||||
return false;
|
||||
|
||||
if (!extractElement(node.Struct()[key], '}'))
|
||||
if(!extractElement(node.Struct()[key], '}'))
|
||||
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]);
|
||||
node.Struct()[key].setOverrideFlag(overrideFlag);
|
||||
|
||||
if (input[pos] == '}')
|
||||
if(input[pos] == '}')
|
||||
{
|
||||
pos++;
|
||||
return true;
|
||||
@ -292,31 +399,40 @@ bool JsonParser::extractStruct(JsonNode &node)
|
||||
}
|
||||
}
|
||||
|
||||
bool JsonParser::extractArray(JsonNode &node)
|
||||
bool JsonParser::extractArray(JsonNode & node)
|
||||
{
|
||||
if(currentDepth > settings.maxDepth)
|
||||
error("Macimum allowed depth of json structure has been reached", true);
|
||||
|
||||
currentDepth++;
|
||||
auto guard = vstd::makeScopeGuard([this]()
|
||||
{
|
||||
currentDepth--;
|
||||
});
|
||||
|
||||
pos++;
|
||||
node.setType(JsonNode::JsonType::DATA_VECTOR);
|
||||
|
||||
if (!extractWhitespace())
|
||||
if(!extractWhitespace())
|
||||
return false;
|
||||
|
||||
//Empty array found
|
||||
if (input[pos] == ']')
|
||||
if(input[pos] == ']')
|
||||
{
|
||||
pos++;
|
||||
return true;
|
||||
}
|
||||
|
||||
while (true)
|
||||
while(true)
|
||||
{
|
||||
//NOTE: currently 50% of time is this vector resizing.
|
||||
//May be useful to use list during parsing and then swap() all items to vector
|
||||
node.Vector().resize(node.Vector().size()+1);
|
||||
node.Vector().resize(node.Vector().size() + 1);
|
||||
|
||||
if (!extractElement(node.Vector().back(), ']'))
|
||||
if(!extractElement(node.Vector().back(), ']'))
|
||||
return false;
|
||||
|
||||
if (input[pos] == ']')
|
||||
if(input[pos] == ']')
|
||||
{
|
||||
pos++;
|
||||
return true;
|
||||
@ -324,74 +440,87 @@ bool JsonParser::extractArray(JsonNode &node)
|
||||
}
|
||||
}
|
||||
|
||||
bool JsonParser::extractElement(JsonNode &node, char terminator)
|
||||
bool JsonParser::extractElement(JsonNode & node, char terminator)
|
||||
{
|
||||
if (!extractValue(node))
|
||||
if(!extractValue(node))
|
||||
return false;
|
||||
|
||||
if (!extractWhitespace())
|
||||
if(!extractWhitespace())
|
||||
return false;
|
||||
|
||||
bool comma = (input[pos] == ',');
|
||||
if (comma )
|
||||
if(comma)
|
||||
{
|
||||
pos++;
|
||||
if (!extractWhitespace())
|
||||
if(!extractWhitespace())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input[pos] == terminator)
|
||||
if(input[pos] == terminator)
|
||||
{
|
||||
//FIXME: MOD COMPATIBILITY: Too many of these right now, re-enable later
|
||||
//if (comma)
|
||||
//error("Extra comma found!", true);
|
||||
if(comma && settings.mode < JsonParsingSettings::JsonFormatMode::JSON5)
|
||||
error("Extra comma found!", true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!comma)
|
||||
if(!comma)
|
||||
error("Comma expected!", true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::extractFloat(JsonNode &node)
|
||||
bool JsonParser::extractFloat(JsonNode & node)
|
||||
{
|
||||
//TODO: JSON5 - hexacedimal support
|
||||
//TODO: JSON5 - Numbers may be IEEE 754 positive infinity, negative infinity, and NaN (why?)
|
||||
|
||||
assert(input[pos] == '-' || (input[pos] >= '0' && input[pos] <= '9'));
|
||||
bool negative=false;
|
||||
double result=0;
|
||||
bool negative = false;
|
||||
double result = 0;
|
||||
si64 integerPart = 0;
|
||||
bool isFloat = false;
|
||||
|
||||
if (input[pos] == '-')
|
||||
if(input[pos] == '+')
|
||||
{
|
||||
if(settings.mode < JsonParsingSettings::JsonFormatMode::JSON5)
|
||||
error("Positive numbers should not have plus sign!", true);
|
||||
pos++;
|
||||
}
|
||||
else if(input[pos] == '-')
|
||||
{
|
||||
pos++;
|
||||
negative = true;
|
||||
}
|
||||
|
||||
if (input[pos] < '0' || input[pos] > '9')
|
||||
return error("Number expected!");
|
||||
if(input[pos] < '0' || input[pos] > '9')
|
||||
{
|
||||
if(input[pos] != '.' && settings.mode < JsonParsingSettings::JsonFormatMode::JSON5)
|
||||
return error("Number expected!");
|
||||
}
|
||||
|
||||
//Extract integer part
|
||||
while (input[pos] >= '0' && input[pos] <= '9')
|
||||
while(input[pos] >= '0' && input[pos] <= '9')
|
||||
{
|
||||
integerPart = integerPart*10+(input[pos]-'0');
|
||||
integerPart = integerPart * 10 + (input[pos] - '0');
|
||||
pos++;
|
||||
}
|
||||
|
||||
result = static_cast<double>(integerPart);
|
||||
|
||||
if (input[pos] == '.')
|
||||
if(input[pos] == '.')
|
||||
{
|
||||
//extract fractional part
|
||||
isFloat = true;
|
||||
pos++;
|
||||
double fractMult = 0.1;
|
||||
if (input[pos] < '0' || input[pos] > '9')
|
||||
|
||||
if(settings.mode < JsonParsingSettings::JsonFormatMode::JSON5 && (input[pos] < '0' || input[pos] > '9'))
|
||||
return error("Decimal part expected!");
|
||||
|
||||
while (input[pos] >= '0' && input[pos] <= '9')
|
||||
while(input[pos] >= '0' && input[pos] <= '9')
|
||||
{
|
||||
result = result + fractMult*(input[pos]-'0');
|
||||
result = result + fractMult * (input[pos] - '0');
|
||||
fractMult /= 10;
|
||||
pos++;
|
||||
}
|
||||
@ -415,12 +544,12 @@ bool JsonParser::extractFloat(JsonNode &node)
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (input[pos] < '0' || input[pos] > '9')
|
||||
if(input[pos] < '0' || input[pos] > '9')
|
||||
return error("Exponential part expected!");
|
||||
|
||||
while (input[pos] >= '0' && input[pos] <= '9')
|
||||
while(input[pos] >= '0' && input[pos] <= '9')
|
||||
{
|
||||
power = power*10 + (input[pos]-'0');
|
||||
power = power * 10 + (input[pos] - '0');
|
||||
pos++;
|
||||
}
|
||||
|
||||
@ -450,13 +579,15 @@ bool JsonParser::extractFloat(JsonNode &node)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::error(const std::string &message, bool warning)
|
||||
bool JsonParser::error(const std::string & message, bool warning)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
std::string type(warning?" warning: ":" error: ");
|
||||
if(settings.strict)
|
||||
throw JsonFormatException(message);
|
||||
|
||||
stream << "At line " << lineCount << ", position "<<pos-lineStart
|
||||
<< type << message <<"\n";
|
||||
std::ostringstream stream;
|
||||
std::string type(warning ? " warning: " : " error: ");
|
||||
|
||||
stream << "At line " << lineCount << ", position " << pos - lineStart << type << message << "\n";
|
||||
errors += stream.str();
|
||||
|
||||
return warning;
|
||||
|
@ -13,64 +13,42 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
//Tiny string class that uses const char* as data for speed, members are private
|
||||
//for ease of debugging and some compatibility with std::string
|
||||
class constString
|
||||
{
|
||||
const char *data;
|
||||
const size_t datasize;
|
||||
|
||||
public:
|
||||
constString(const char * inputString, size_t stringSize):
|
||||
data(inputString),
|
||||
datasize(stringSize)
|
||||
{
|
||||
}
|
||||
|
||||
inline size_t size() const
|
||||
{
|
||||
return datasize;
|
||||
};
|
||||
|
||||
inline const char& operator[] (size_t position)
|
||||
{
|
||||
assert (position < datasize);
|
||||
return data[position];
|
||||
}
|
||||
};
|
||||
|
||||
//Internal class for string -> JsonNode conversion
|
||||
class JsonParser
|
||||
{
|
||||
std::string errors; // Contains description of all encountered errors
|
||||
constString input; // Input data
|
||||
ui32 lineCount; // Currently parsed line, starting from 1
|
||||
size_t lineStart; // Position of current line start
|
||||
size_t pos; // Current position of parser
|
||||
const JsonParsingSettings settings;
|
||||
|
||||
std::string errors; // Contains description of all encountered errors
|
||||
std::string_view input; // Input data
|
||||
uint32_t lineCount; // Currently parsed line, starting from 1
|
||||
uint32_t currentDepth;
|
||||
size_t lineStart; // Position of current line start
|
||||
size_t pos; // Current position of parser
|
||||
|
||||
//Helpers
|
||||
bool extractEscaping(std::string &str);
|
||||
bool extractLiteral(const std::string &literal);
|
||||
bool extractString(std::string &string);
|
||||
bool extractEscaping(std::string & str);
|
||||
bool extractLiteral(std::string & literal);
|
||||
bool extractAndCompareLiteral(const std::string & expectedLiteral);
|
||||
bool extractString(std::string & string);
|
||||
bool extractWhitespace(bool verbose = true);
|
||||
bool extractSeparator();
|
||||
bool extractElement(JsonNode &node, char terminator);
|
||||
bool extractElement(JsonNode & node, char terminator);
|
||||
|
||||
//Methods for extracting JSON data
|
||||
bool extractArray(JsonNode &node);
|
||||
bool extractFalse(JsonNode &node);
|
||||
bool extractFloat(JsonNode &node);
|
||||
bool extractNull(JsonNode &node);
|
||||
bool extractString(JsonNode &node);
|
||||
bool extractStruct(JsonNode &node);
|
||||
bool extractTrue(JsonNode &node);
|
||||
bool extractValue(JsonNode &node);
|
||||
bool extractArray(JsonNode & node);
|
||||
bool extractFalse(JsonNode & node);
|
||||
bool extractFloat(JsonNode & node);
|
||||
bool extractNull(JsonNode & node);
|
||||
bool extractString(JsonNode & node);
|
||||
bool extractStruct(JsonNode & node);
|
||||
bool extractTrue(JsonNode & node);
|
||||
bool extractValue(JsonNode & node);
|
||||
|
||||
//Add error\warning message to list
|
||||
bool error(const std::string &message, bool warning=false);
|
||||
bool error(const std::string & message, bool warning = false);
|
||||
|
||||
public:
|
||||
JsonParser(const char * inputString, size_t stringSize);
|
||||
JsonParser(const std::byte * inputString, size_t stringSize, const JsonParsingSettings & settings);
|
||||
|
||||
/// do actual parsing. filename is name of file that will printed to console if any errors were found
|
||||
JsonNode parse(const std::string & fileName);
|
||||
|
@ -235,9 +235,9 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
filteredAnyOf.insert(subset.begin(), subset.end());
|
||||
}
|
||||
|
||||
vstd::erase_if(filteredTypes, [&](const IdentifierType & value)
|
||||
vstd::erase_if(filteredTypes, [&filteredAnyOf](const IdentifierType & filteredValue)
|
||||
{
|
||||
return filteredAnyOf.count(value) == 0;
|
||||
return filteredAnyOf.count(filteredValue) == 0;
|
||||
});
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -9,9 +9,9 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GameCallbackHolder.h"
|
||||
#include "GameConstants.h"
|
||||
#include "ResourceSet.h"
|
||||
#include "GameCallbackHolder.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -23,7 +23,7 @@ struct Bonus;
|
||||
struct Component;
|
||||
class CStackBasicDescriptor;
|
||||
|
||||
class DLL_LINKAGE JsonRandom : public GameCallbackHolder
|
||||
class JsonRandom : public GameCallbackHolder
|
||||
{
|
||||
public:
|
||||
using Variables = std::map<std::string, int>;
|
||||
@ -46,7 +46,7 @@ private:
|
||||
public:
|
||||
using GameCallbackHolder::GameCallbackHolder;
|
||||
|
||||
struct DLL_LINKAGE RandomStackInfo
|
||||
struct RandomStackInfo
|
||||
{
|
||||
std::vector<const CCreature *> allowedCreatures;
|
||||
si32 minAmount;
|
||||
|
@ -13,38 +13,12 @@
|
||||
|
||||
#include "JsonValidator.h"
|
||||
|
||||
#include "../ScopeGuard.h"
|
||||
#include "../bonuses/BonusParams.h"
|
||||
#include "../bonuses/Bonus.h"
|
||||
#include "../bonuses/Limiters.h"
|
||||
#include "../bonuses/Propagators.h"
|
||||
#include "../bonuses/Updaters.h"
|
||||
#include "../filesystem/Filesystem.h"
|
||||
#include "../modding/IdentifierStorage.h"
|
||||
#include "../VCMI_Lib.h" //for identifier resolution
|
||||
#include "../CGeneralTextHandler.h"
|
||||
#include "../constants/StringConstants.h"
|
||||
#include "../battle/BattleHex.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
VCMI_LIB_USING_NAMESPACE
|
||||
|
||||
static const JsonNode nullNode;
|
||||
|
||||
//returns first Key with value equal to given one
|
||||
template<class Key, class Val>
|
||||
Key reverseMapFirst(const Val & val, const std::map<Key, Val> & map)
|
||||
{
|
||||
for(auto it : map)
|
||||
{
|
||||
if(it.second == val)
|
||||
{
|
||||
return it.first;
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
return "";
|
||||
}
|
||||
|
||||
static JsonNode getDefaultValue(const JsonNode & schema, std::string fieldName)
|
||||
{
|
||||
const JsonNode & fieldProps = schema["properties"][fieldName];
|
||||
@ -76,8 +50,8 @@ static void eraseOptionalNodes(JsonNode & node, const JsonNode & schema)
|
||||
for(const auto & entry : schema["required"].Vector())
|
||||
foundEntries.insert(entry.String());
|
||||
|
||||
vstd::erase_if(node.Struct(), [&](const auto & node){
|
||||
return !vstd::contains(foundEntries, node.first);
|
||||
vstd::erase_if(node.Struct(), [&foundEntries](const auto & structEntry){
|
||||
return !vstd::contains(foundEntries, structEntry.first);
|
||||
});
|
||||
}
|
||||
|
||||
@ -117,6 +91,8 @@ static void maximizeNode(JsonNode & node, const JsonNode & schema)
|
||||
eraseOptionalNodes(node, schema);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void JsonUtils::minimize(JsonNode & node, const std::string & schemaName)
|
||||
{
|
||||
minimizeNode(node, getSchema(schemaName));
|
||||
@ -129,12 +105,13 @@ void JsonUtils::maximize(JsonNode & node, const std::string & schemaName)
|
||||
|
||||
bool JsonUtils::validate(const JsonNode & node, const std::string & schemaName, const std::string & dataName)
|
||||
{
|
||||
std::string log = Validation::check(schemaName, node);
|
||||
JsonValidator validator;
|
||||
std::string log = validator.check(schemaName, node);
|
||||
if (!log.empty())
|
||||
{
|
||||
logMod->warn("Data in %s is invalid!", dataName);
|
||||
logMod->warn(log);
|
||||
logMod->trace("%s json: %s", dataName, node.toJson(true));
|
||||
logMod->trace("%s json: %s", dataName, node.toCompactString());
|
||||
}
|
||||
return log.empty();
|
||||
}
|
||||
@ -223,14 +200,14 @@ void JsonUtils::merge(JsonNode & dest, JsonNode & source, bool ignoreOverride, b
|
||||
}
|
||||
case JsonNode::JsonType::DATA_STRUCT:
|
||||
{
|
||||
if(!ignoreOverride && vstd::contains(source.flags, "override"))
|
||||
if(!ignoreOverride && source.getOverrideFlag())
|
||||
{
|
||||
std::swap(dest, source);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (copyMeta)
|
||||
dest.meta = source.meta;
|
||||
dest.setModScope(source.getModScope(), false);
|
||||
|
||||
//recursively merge all entries from struct
|
||||
for(auto & node : source.Struct())
|
||||
@ -253,90 +230,6 @@ void JsonUtils::inherit(JsonNode & descendant, const JsonNode & base)
|
||||
std::swap(descendant, inheritedNode);
|
||||
}
|
||||
|
||||
JsonNode JsonUtils::intersect(const std::vector<JsonNode> & nodes, bool pruneEmpty)
|
||||
{
|
||||
if(nodes.empty())
|
||||
return nullNode;
|
||||
|
||||
JsonNode result = nodes[0];
|
||||
for(int i = 1; i < nodes.size(); i++)
|
||||
{
|
||||
if(result.isNull())
|
||||
break;
|
||||
result = JsonUtils::intersect(result, nodes[i], pruneEmpty);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
JsonNode JsonUtils::intersect(const JsonNode & a, const JsonNode & b, bool pruneEmpty)
|
||||
{
|
||||
if(a.getType() == JsonNode::JsonType::DATA_STRUCT && b.getType() == JsonNode::JsonType::DATA_STRUCT)
|
||||
{
|
||||
// intersect individual properties
|
||||
JsonNode result(JsonNode::JsonType::DATA_STRUCT);
|
||||
for(const auto & property : a.Struct())
|
||||
{
|
||||
if(vstd::contains(b.Struct(), property.first))
|
||||
{
|
||||
JsonNode propertyIntersect = JsonUtils::intersect(property.second, b.Struct().find(property.first)->second);
|
||||
if(pruneEmpty && !propertyIntersect.containsBaseData())
|
||||
continue;
|
||||
result[property.first] = propertyIntersect;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// not a struct - same or different, no middle ground
|
||||
if(a == b)
|
||||
return a;
|
||||
}
|
||||
return nullNode;
|
||||
}
|
||||
|
||||
JsonNode JsonUtils::difference(const JsonNode & node, const JsonNode & base)
|
||||
{
|
||||
auto addsInfo = [](JsonNode diff) -> bool
|
||||
{
|
||||
switch(diff.getType())
|
||||
{
|
||||
case JsonNode::JsonType::DATA_NULL:
|
||||
return false;
|
||||
case JsonNode::JsonType::DATA_STRUCT:
|
||||
return !diff.Struct().empty();
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
if(node.getType() == JsonNode::JsonType::DATA_STRUCT && base.getType() == JsonNode::JsonType::DATA_STRUCT)
|
||||
{
|
||||
// subtract individual properties
|
||||
JsonNode result(JsonNode::JsonType::DATA_STRUCT);
|
||||
for(const auto & property : node.Struct())
|
||||
{
|
||||
if(vstd::contains(base.Struct(), property.first))
|
||||
{
|
||||
const JsonNode propertyDifference = JsonUtils::difference(property.second, base.Struct().find(property.first)->second);
|
||||
if(addsInfo(propertyDifference))
|
||||
result[property.first] = propertyDifference;
|
||||
}
|
||||
else
|
||||
{
|
||||
result[property.first] = property.second;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(node == base)
|
||||
return nullNode;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
JsonNode JsonUtils::assembleFromFiles(const std::vector<std::string> & files)
|
||||
{
|
||||
bool isValid = false;
|
||||
@ -365,43 +258,11 @@ JsonNode JsonUtils::assembleFromFiles(const std::string & filename)
|
||||
|
||||
for(auto & loader : CResourceHandler::get()->getResourcesWithName(resID))
|
||||
{
|
||||
// FIXME: some way to make this code more readable
|
||||
auto stream = loader->load(resID);
|
||||
std::unique_ptr<ui8[]> textData(new ui8[stream->getSize()]);
|
||||
stream->read(textData.get(), stream->getSize());
|
||||
|
||||
JsonNode section(reinterpret_cast<char *>(textData.get()), stream->getSize());
|
||||
auto textData = loader->load(resID)->readAll();
|
||||
JsonNode section(reinterpret_cast<std::byte *>(textData.first.get()), textData.second);
|
||||
merge(result, section);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DLL_LINKAGE JsonNode JsonUtils::boolNode(bool value)
|
||||
{
|
||||
JsonNode node;
|
||||
node.Bool() = value;
|
||||
return node;
|
||||
}
|
||||
|
||||
DLL_LINKAGE JsonNode JsonUtils::floatNode(double value)
|
||||
{
|
||||
JsonNode node;
|
||||
node.Float() = value;
|
||||
return node;
|
||||
}
|
||||
|
||||
DLL_LINKAGE JsonNode JsonUtils::stringNode(const std::string & value)
|
||||
{
|
||||
JsonNode node;
|
||||
node.String() = value;
|
||||
return node;
|
||||
}
|
||||
|
||||
DLL_LINKAGE JsonNode JsonUtils::intNode(si64 value)
|
||||
{
|
||||
JsonNode node;
|
||||
node.Integer() = value;
|
||||
return node;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -40,22 +40,6 @@ namespace JsonUtils
|
||||
*/
|
||||
DLL_LINKAGE void inherit(JsonNode & descendant, const JsonNode & base);
|
||||
|
||||
/**
|
||||
* @brief construct node representing the common structure of input nodes
|
||||
* @param pruneEmpty - omit common properties whose intersection is empty
|
||||
* different types: null
|
||||
* struct: recursive intersect on common properties
|
||||
* other: input if equal, null otherwise
|
||||
*/
|
||||
DLL_LINKAGE JsonNode intersect(const JsonNode & a, const JsonNode & b, bool pruneEmpty = true);
|
||||
DLL_LINKAGE JsonNode intersect(const std::vector<JsonNode> & nodes, bool pruneEmpty = true);
|
||||
|
||||
/**
|
||||
* @brief construct node representing the difference "node - base"
|
||||
* merging difference with base gives node
|
||||
*/
|
||||
DLL_LINKAGE JsonNode difference(const JsonNode & node, const JsonNode & base);
|
||||
|
||||
/**
|
||||
* @brief generate one Json structure from multiple files
|
||||
* @param files - list of filenames with parts of json structure
|
||||
@ -88,12 +72,6 @@ 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);
|
||||
|
||||
/// for easy construction of JsonNodes; helps with inserting primitives into vector node
|
||||
DLL_LINKAGE JsonNode boolNode(bool value);
|
||||
DLL_LINKAGE JsonNode floatNode(double value);
|
||||
DLL_LINKAGE JsonNode stringNode(const std::string & value);
|
||||
DLL_LINKAGE JsonNode intNode(si64 value);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,28 +13,23 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
//Internal class for Json validation. Mostly compilant with json-schema v4 draft
|
||||
namespace Validation
|
||||
/// Class for Json validation. Mostly compilant with json-schema v6 draf
|
||||
struct JsonValidator
|
||||
{
|
||||
/// struct used to pass data around during validation
|
||||
struct ValidationData
|
||||
{
|
||||
/// path from root node to current one.
|
||||
/// JsonNode is used as variant - either string (name of node) or as float (index in list)
|
||||
std::vector<JsonNode> currentPath;
|
||||
/// path from root node to current one.
|
||||
/// JsonNode is used as variant - either string (name of node) or as float (index in list)
|
||||
std::vector<JsonNode> currentPath;
|
||||
|
||||
/// Stack of used schemas. Last schema is the one used currently.
|
||||
/// May contain multiple items in case if remote references were found
|
||||
std::vector<std::string> usedSchemas;
|
||||
/// Stack of used schemas. Last schema is the one used currently.
|
||||
/// May contain multiple items in case if remote references were found
|
||||
std::vector<std::string> usedSchemas;
|
||||
|
||||
/// generates error message
|
||||
std::string makeErrorMessage(const std::string &message);
|
||||
};
|
||||
/// generates error message
|
||||
std::string makeErrorMessage(const std::string &message);
|
||||
|
||||
using TFormatValidator = std::function<std::string(const JsonNode &)>;
|
||||
using TFormatMap = std::unordered_map<std::string, TFormatValidator>;
|
||||
using TFieldValidator = std::function<std::string(ValidationData &, const JsonNode &, const JsonNode &, const JsonNode &)>;
|
||||
using TFieldValidator = std::function<std::string(JsonValidator &, const JsonNode &, const JsonNode &, const JsonNode &)>;
|
||||
using TValidatorMap = std::unordered_map<std::string, TFieldValidator>;
|
||||
|
||||
/// map of known fields in schema
|
||||
@ -42,8 +37,7 @@ namespace Validation
|
||||
const TFormatMap & getKnownFormats();
|
||||
|
||||
std::string check(const std::string & schemaName, const JsonNode & data);
|
||||
std::string check(const std::string & schemaName, const JsonNode & data, ValidationData & validator);
|
||||
std::string check(const JsonNode & schema, const JsonNode & data, ValidationData & validator);
|
||||
}
|
||||
std::string check(const JsonNode & schema, const JsonNode & data);
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -16,31 +16,29 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
template<typename Iterator>
|
||||
void JsonWriter::writeContainer(Iterator begin, Iterator end)
|
||||
{
|
||||
if (begin == end)
|
||||
if(begin == end)
|
||||
return;
|
||||
|
||||
prefix += '\t';
|
||||
|
||||
writeEntry(begin++);
|
||||
|
||||
while (begin != end)
|
||||
while(begin != end)
|
||||
{
|
||||
out << (compactMode ? ", " : ",\n");
|
||||
writeEntry(begin++);
|
||||
}
|
||||
|
||||
out << (compactMode ? "" : "\n");
|
||||
prefix.resize(prefix.size()-1);
|
||||
prefix.resize(prefix.size() - 1);
|
||||
}
|
||||
|
||||
void JsonWriter::writeEntry(JsonMap::const_iterator entry)
|
||||
{
|
||||
if(!compactMode)
|
||||
{
|
||||
if (!entry->second.meta.empty())
|
||||
out << prefix << " // " << entry->second.meta << "\n";
|
||||
if(!entry->second.flags.empty())
|
||||
out << prefix << " // flags: " << boost::algorithm::join(entry->second.flags, ", ") << "\n";
|
||||
if(!entry->second.getModScope().empty())
|
||||
out << prefix << " // " << entry->second.getModScope() << "\n";
|
||||
out << prefix;
|
||||
}
|
||||
writeString(entry->first);
|
||||
@ -52,30 +50,25 @@ void JsonWriter::writeEntry(JsonVector::const_iterator entry)
|
||||
{
|
||||
if(!compactMode)
|
||||
{
|
||||
if (!entry->meta.empty())
|
||||
out << prefix << " // " << entry->meta << "\n";
|
||||
if(!entry->flags.empty())
|
||||
out << prefix << " // flags: " << boost::algorithm::join(entry->flags, ", ") << "\n";
|
||||
if(!entry->getModScope().empty())
|
||||
out << prefix << " // " << entry->getModScope() << "\n";
|
||||
out << prefix;
|
||||
}
|
||||
writeNode(*entry);
|
||||
}
|
||||
|
||||
void JsonWriter::writeString(const std::string &string)
|
||||
void JsonWriter::writeString(const std::string & string)
|
||||
{
|
||||
static const std::string escaped = "\"\\\b\f\n\r\t/";
|
||||
static const std::string escaped = "\"\\\b\f\n\r\t";
|
||||
static const std::array escapedCode = {'\"', '\\', 'b', 'f', 'n', 'r', 't'};
|
||||
|
||||
static const std::array<char, 8> escaped_code = {'\"', '\\', 'b', 'f', 'n', 'r', 't', '/'};
|
||||
|
||||
out <<'\"';
|
||||
out << '\"';
|
||||
size_t pos = 0;
|
||||
size_t start = 0;
|
||||
for (; pos<string.size(); pos++)
|
||||
for(; pos < string.size(); pos++)
|
||||
{
|
||||
//we need to check if special character was been already escaped
|
||||
if((string[pos] == '\\')
|
||||
&& (pos+1 < string.size())
|
||||
&& (std::find(escaped_code.begin(), escaped_code.end(), string[pos+1]) != escaped_code.end()) )
|
||||
if((string[pos] == '\\') && (pos + 1 < string.size()) && (std::find(escapedCode.begin(), escapedCode.end(), string[pos + 1]) != escapedCode.end()))
|
||||
{
|
||||
pos++; //write unchanged, next simbol also checked
|
||||
}
|
||||
@ -83,20 +76,19 @@ void JsonWriter::writeString(const std::string &string)
|
||||
{
|
||||
size_t escapedPos = escaped.find(string[pos]);
|
||||
|
||||
if (escapedPos != std::string::npos)
|
||||
if(escapedPos != std::string::npos)
|
||||
{
|
||||
out.write(string.data()+start, pos - start);
|
||||
out << '\\' << escaped_code[escapedPos];
|
||||
start = pos+1;
|
||||
out.write(string.data() + start, pos - start);
|
||||
out << '\\' << escapedCode[escapedPos];
|
||||
start = pos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
out.write(string.data()+start, pos - start);
|
||||
out <<'\"';
|
||||
out.write(string.data() + start, pos - start);
|
||||
out << '\"';
|
||||
}
|
||||
|
||||
void JsonWriter::writeNode(const JsonNode &node)
|
||||
void JsonWriter::writeNode(const JsonNode & node)
|
||||
{
|
||||
bool originalMode = compactMode;
|
||||
if(compact && !compactMode && node.isCompact())
|
||||
@ -104,40 +96,48 @@ void JsonWriter::writeNode(const JsonNode &node)
|
||||
|
||||
switch(node.getType())
|
||||
{
|
||||
break; case JsonNode::JsonType::DATA_NULL:
|
||||
case JsonNode::JsonType::DATA_NULL:
|
||||
out << "null";
|
||||
break;
|
||||
|
||||
break; case JsonNode::JsonType::DATA_BOOL:
|
||||
if (node.Bool())
|
||||
case JsonNode::JsonType::DATA_BOOL:
|
||||
if(node.Bool())
|
||||
out << "true";
|
||||
else
|
||||
out << "false";
|
||||
break;
|
||||
|
||||
break; case JsonNode::JsonType::DATA_FLOAT:
|
||||
case JsonNode::JsonType::DATA_FLOAT:
|
||||
out << node.Float();
|
||||
break;
|
||||
|
||||
break; case JsonNode::JsonType::DATA_STRING:
|
||||
case JsonNode::JsonType::DATA_STRING:
|
||||
writeString(node.String());
|
||||
break;
|
||||
|
||||
break; case JsonNode::JsonType::DATA_VECTOR:
|
||||
case JsonNode::JsonType::DATA_VECTOR:
|
||||
out << "[" << (compactMode ? " " : "\n");
|
||||
writeContainer(node.Vector().begin(), node.Vector().end());
|
||||
out << (compactMode ? " " : prefix) << "]";
|
||||
break;
|
||||
|
||||
break; case JsonNode::JsonType::DATA_STRUCT:
|
||||
case JsonNode::JsonType::DATA_STRUCT:
|
||||
out << "{" << (compactMode ? " " : "\n");
|
||||
writeContainer(node.Struct().begin(), node.Struct().end());
|
||||
out << (compactMode ? " " : prefix) << "}";
|
||||
break;
|
||||
|
||||
break; case JsonNode::JsonType::DATA_INTEGER:
|
||||
case JsonNode::JsonType::DATA_INTEGER:
|
||||
out << node.Integer();
|
||||
break;
|
||||
}
|
||||
|
||||
compactMode = originalMode;
|
||||
}
|
||||
|
||||
JsonWriter::JsonWriter(std::ostream & output, bool compact)
|
||||
: out(output), compact(compact)
|
||||
: out(output)
|
||||
, compact(compact)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ class JsonWriter
|
||||
bool compact;
|
||||
//tracks whether we are currently using single-line format
|
||||
bool compactMode = false;
|
||||
|
||||
public:
|
||||
template<typename Iterator>
|
||||
void writeContainer(Iterator begin, Iterator end);
|
||||
|
@ -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());
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
|
@ -220,13 +220,10 @@ void CGMine::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
{
|
||||
if(handler.saving)
|
||||
{
|
||||
JsonNode node(JsonNode::JsonType::DATA_VECTOR);
|
||||
JsonNode node;
|
||||
for(const auto & resID : abandonedMineResources)
|
||||
{
|
||||
JsonNode one(JsonNode::JsonType::DATA_STRING);
|
||||
one.String() = GameConstants::RESOURCE_NAMES[resID.getNum()];
|
||||
node.Vector().push_back(one);
|
||||
}
|
||||
node.Vector().emplace_back(GameConstants::RESOURCE_NAMES[resID.getNum()]);
|
||||
|
||||
handler.serializeRaw("possibleResources", node, std::nullopt);
|
||||
}
|
||||
else
|
||||
|
@ -354,11 +354,7 @@ void ObjectTemplate::writeJson(JsonNode & node, const bool withTerrain) const
|
||||
JsonVector & data = node["allowedTerrains"].Vector();
|
||||
|
||||
for(auto type : allowedTerrains)
|
||||
{
|
||||
JsonNode value(JsonNode::JsonType::DATA_STRING);
|
||||
value.String() = VLC->terrainTypeHandler->getById(type)->getJsonKey();
|
||||
data.push_back(value);
|
||||
}
|
||||
data.emplace_back(VLC->terrainTypeHandler->getById(type)->getJsonKey());
|
||||
}
|
||||
}
|
||||
|
||||
@ -398,13 +394,11 @@ void ObjectTemplate::writeJson(JsonNode & node, const bool withTerrain) const
|
||||
|
||||
for(size_t i=0; i < height; i++)
|
||||
{
|
||||
JsonNode lineNode(JsonNode::JsonType::DATA_STRING);
|
||||
|
||||
std::string & line = lineNode.String();
|
||||
std::string line;
|
||||
line.resize(width);
|
||||
for(size_t j=0; j < width; j++)
|
||||
line[j] = tileToChar(usedTiles[height - 1 - i][width - 1 - j]);
|
||||
mask.push_back(lineNode);
|
||||
mask.emplace_back(line);
|
||||
}
|
||||
|
||||
if(printPriority != 0)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -545,13 +545,10 @@ void CMapFormatJson::writeTeams(JsonSerializer & handler)
|
||||
|
||||
for(const std::set<PlayerColor> & teamData : teamsData)
|
||||
{
|
||||
JsonNode team(JsonNode::JsonType::DATA_VECTOR);
|
||||
JsonNode team;
|
||||
for(const PlayerColor & player : teamData)
|
||||
{
|
||||
JsonNode member(JsonNode::JsonType::DATA_STRING);
|
||||
member.String() = GameConstants::PLAYER_COLOR_NAMES[player.getNum()];
|
||||
team.Vector().push_back(std::move(member));
|
||||
}
|
||||
team.Vector().emplace_back(GameConstants::PLAYER_COLOR_NAMES[player.getNum()]);
|
||||
|
||||
dest.Vector().push_back(std::move(team));
|
||||
}
|
||||
handler.serializeRaw("teams", dest, std::nullopt);
|
||||
@ -586,7 +583,7 @@ void CMapFormatJson::readTriggeredEvent(TriggeredEvent & event, const JsonNode &
|
||||
|
||||
void CMapFormatJson::writeTriggeredEvents(JsonSerializer & handler)
|
||||
{
|
||||
JsonNode triggeredEvents(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode triggeredEvents;
|
||||
|
||||
for(const auto & event : mapHeader->triggeredEvents)
|
||||
writeTriggeredEvent(event, triggeredEvents[event.identifier]);
|
||||
@ -657,7 +654,7 @@ void CMapFormatJson::writeDisposedHeroes(JsonSerializeFormat & handler)
|
||||
|
||||
auto definition = definitions->enterStruct(type);
|
||||
|
||||
JsonNode players(JsonNode::JsonType::DATA_VECTOR);
|
||||
JsonNode players;
|
||||
definition->serializeIdArray("availableFor", hero.players);
|
||||
}
|
||||
}
|
||||
@ -812,7 +809,7 @@ JsonNode CMapLoaderJson::getFromArchive(const std::string & archiveFilename)
|
||||
|
||||
auto data = loader.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;
|
||||
}
|
||||
@ -1049,7 +1046,7 @@ void CMapLoaderJson::MapObjectLoader::construct()
|
||||
if(typeName.empty())
|
||||
{
|
||||
logGlobal->error("Object type missing");
|
||||
logGlobal->debug(configuration.toJson());
|
||||
logGlobal->debug(configuration.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1069,7 +1066,7 @@ void CMapLoaderJson::MapObjectLoader::construct()
|
||||
else if(subtypeName.empty())
|
||||
{
|
||||
logGlobal->error("Object subtype missing");
|
||||
logGlobal->debug(configuration.toJson());
|
||||
logGlobal->debug(configuration.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1329,7 +1326,7 @@ void CMapSaverJson::writeTerrain()
|
||||
void CMapSaverJson::writeObjects()
|
||||
{
|
||||
logGlobal->trace("Saving objects");
|
||||
JsonNode data(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode data;
|
||||
|
||||
JsonSerializer handler(mapObjectResolver.get(), data);
|
||||
|
||||
@ -1343,7 +1340,7 @@ void CMapSaverJson::writeObjects()
|
||||
|
||||
if(map->grailPos.valid())
|
||||
{
|
||||
JsonNode grail(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode grail;
|
||||
grail["type"].String() = "grail";
|
||||
|
||||
grail["x"].Float() = map->grailPos.x;
|
||||
|
@ -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())};
|
||||
|
@ -226,7 +226,10 @@ void CModHandler::loadOneMod(std::string modName, const std::string & parent, co
|
||||
|
||||
if(CResourceHandler::get("initial")->existsResource(CModInfo::getModFile(modFullName)))
|
||||
{
|
||||
CModInfo mod(modFullName, modSettings[modName], JsonNode(CModInfo::getModFile(modFullName)));
|
||||
JsonParsingSettings settings;
|
||||
settings.mode = JsonParsingSettings::JsonFormatMode::JSON; // TODO: remove once Android launcher with its strict parser is gone
|
||||
|
||||
CModInfo mod(modFullName, modSettings[modName], JsonNode(CModInfo::getModFile(modFullName), settings));
|
||||
if (!parent.empty()) // this is submod, add parent to dependencies
|
||||
mod.dependencies.insert(parent);
|
||||
|
||||
@ -512,7 +515,7 @@ void CModHandler::afterLoad(bool onlyEssential)
|
||||
if(!onlyEssential)
|
||||
{
|
||||
std::fstream file(CResourceHandler::get()->getResourceName(ResourcePath("config/modSettings.json"))->c_str(), std::ofstream::out | std::ofstream::trunc);
|
||||
file << modSettings.toJson();
|
||||
file << modSettings.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -35,7 +35,8 @@ enum class ESerializationVersion : int32_t
|
||||
RELEASE_143, // 832 +text container in campaigns, +starting hero in RMG options
|
||||
HAS_EXTRA_OPTIONS, // 833 +extra options struct as part of startinfo
|
||||
DESTROYED_OBJECTS, // 834 +list of objects destroyed by player
|
||||
CAMPAIGN_MAP_TRANSLATIONS,
|
||||
CAMPAIGN_MAP_TRANSLATIONS, // 835 +campaigns include translations for its maps
|
||||
JSON_FLAGS, // 836 json uses new format for flags
|
||||
|
||||
CURRENT = CAMPAIGN_MAP_TRANSLATIONS
|
||||
CURRENT = JSON_FLAGS
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -60,11 +60,7 @@ void JsonSerializer::serializeInternal(const std::string & fieldName, std::vecto
|
||||
data.reserve(value.size());
|
||||
|
||||
for(const si32 rawId : value)
|
||||
{
|
||||
JsonNode jsonElement(JsonNode::JsonType::DATA_STRING);
|
||||
jsonElement.String() = encoder(rawId);
|
||||
data.push_back(std::move(jsonElement));
|
||||
}
|
||||
data.emplace_back(rawId);
|
||||
}
|
||||
|
||||
void JsonSerializer::serializeInternal(const std::string & fieldName, std::vector<std::string> & value)
|
||||
@ -76,11 +72,7 @@ void JsonSerializer::serializeInternal(const std::string & fieldName, std::vecto
|
||||
data.reserve(value.size());
|
||||
|
||||
for(const auto & rawId : value)
|
||||
{
|
||||
JsonNode jsonElement(JsonNode::JsonType::DATA_STRING);
|
||||
jsonElement.String() = rawId;
|
||||
data.push_back(std::move(jsonElement));
|
||||
}
|
||||
data.emplace_back(rawId);
|
||||
}
|
||||
|
||||
void JsonSerializer::serializeInternal(std::string & value)
|
||||
@ -183,11 +175,7 @@ void JsonSerializer::writeLICPartBuffer(const std::string & fieldName, const std
|
||||
auto & target = currentObject->operator[](fieldName)[partName].Vector();
|
||||
|
||||
for(auto & s : buffer)
|
||||
{
|
||||
JsonNode val(JsonNode::JsonType::DATA_STRING);
|
||||
std::swap(val.String(), s);
|
||||
target.push_back(std::move(val));
|
||||
}
|
||||
target.emplace_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -582,7 +582,7 @@ std::vector<JsonNode> CSpellHandler::loadLegacyData()
|
||||
{
|
||||
do
|
||||
{
|
||||
JsonNode lineNode(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode lineNode;
|
||||
|
||||
const auto id = legacyData.size();
|
||||
|
||||
@ -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);
|
||||
});
|
||||
@ -833,7 +833,7 @@ CSpell * CSpellHandler::loadFromJson(const std::string & scope, const JsonNode &
|
||||
{
|
||||
logMod->warn("Spell %s has old target condition format. Expected configuration: ", spell->getNameTranslated());
|
||||
spell->targetCondition = spell->convertTargetCondition(immunities, absoluteImmunities, limiters, absoluteLimiters);
|
||||
logMod->warn("\n\"targetCondition\" : %s", spell->targetCondition.toJson());
|
||||
logMod->warn("\n\"targetCondition\" : %s", spell->targetCondition.toString());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -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)
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct Bonus;
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
|
@ -58,7 +58,7 @@ NetworkConnectionPtr LobbyServer::findGameRoom(const std::string & gameRoomID) c
|
||||
|
||||
void LobbyServer::sendMessage(const NetworkConnectionPtr & target, const JsonNode & json)
|
||||
{
|
||||
target->sendPacket(json.toBytes(true));
|
||||
target->sendPacket(json.toBytes());
|
||||
}
|
||||
|
||||
void LobbyServer::sendAccountCreated(const NetworkConnectionPtr & target, const std::string & accountID, const std::string & accountCookie)
|
||||
|
@ -599,7 +599,7 @@ void Animation::init()
|
||||
std::unique_ptr<ui8[]> textData(new ui8[stream->getSize()]);
|
||||
stream->read(textData.get(), stream->getSize());
|
||||
|
||||
const JsonNode config((char*)textData.get(), stream->getSize());
|
||||
const JsonNode config(reinterpret_cast<const std::byte*>(textData.get()), stream->getSize());
|
||||
|
||||
initFromJson(config);
|
||||
}
|
||||
@ -610,7 +610,7 @@ void Animation::initFromJson(const JsonNode & config)
|
||||
std::string basepath;
|
||||
basepath = config["basepath"].String();
|
||||
|
||||
JsonNode base(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode base;
|
||||
base["margins"] = config["margins"];
|
||||
base["width"] = config["width"];
|
||||
base["height"] = config["height"];
|
||||
@ -622,7 +622,7 @@ void Animation::initFromJson(const JsonNode & config)
|
||||
|
||||
for(const JsonNode & frame : group["frames"].Vector())
|
||||
{
|
||||
JsonNode toAdd(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode toAdd;
|
||||
JsonUtils::inherit(toAdd, base);
|
||||
toAdd["file"].String() = basepath + frame.String();
|
||||
source[groupID].push_back(toAdd);
|
||||
@ -637,7 +637,7 @@ void Animation::initFromJson(const JsonNode & config)
|
||||
if (source[group].size() <= frame)
|
||||
source[group].resize(frame+1);
|
||||
|
||||
JsonNode toAdd(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode toAdd;
|
||||
JsonUtils::inherit(toAdd, base);
|
||||
toAdd["file"].String() = basepath + node["file"].String();
|
||||
source[group][frame] = toAdd;
|
||||
|
@ -96,7 +96,7 @@ QVariant JsonFromFile(QString filename)
|
||||
}
|
||||
else
|
||||
{
|
||||
JsonNode node(data.data(), data.size());
|
||||
JsonNode node(reinterpret_cast<const std::byte*>(data.data()), data.size());
|
||||
return toVariant(node);
|
||||
}
|
||||
}
|
||||
@ -122,7 +122,7 @@ JsonNode toJson(QVariant object)
|
||||
void JsonToFile(QString filename, QVariant object)
|
||||
{
|
||||
std::fstream file(qstringToPath(filename).c_str(), std::ios::out | std::ios_base::binary);
|
||||
file << toJson(object).toJson();
|
||||
file << toJson(object).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ MainWindow::MainWindow(QWidget* parent) :
|
||||
|
||||
// Initialize logging based on settings
|
||||
logConfig->configure();
|
||||
logGlobal->debug("settings = %s", settings.toJsonNode().toJson());
|
||||
logGlobal->debug("settings = %s", settings.toJsonNode().toString());
|
||||
|
||||
// Some basic data validation to produce better error messages in cases of incorrect install
|
||||
auto testFile = [](std::string filename, std::string message) -> bool
|
||||
|
@ -24,7 +24,7 @@ void Translations::cleanupRemovedItems(CMap & map)
|
||||
|
||||
for(auto & translations : map.translations.Struct())
|
||||
{
|
||||
auto updateTranslations = JsonNode(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode updateTranslations;
|
||||
for(auto & s : translations.second.Struct())
|
||||
{
|
||||
for(auto part : QString::fromStdString(s.first).split('.'))
|
||||
@ -44,7 +44,7 @@ void Translations::cleanupRemovedItems(CMap & map, const std::string & pattern)
|
||||
{
|
||||
for(auto & translations : map.translations.Struct())
|
||||
{
|
||||
auto updateTranslations = JsonNode(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode updateTranslations;
|
||||
for(auto & s : translations.second.Struct())
|
||||
{
|
||||
if(s.first.find(pattern) == std::string::npos)
|
||||
@ -171,7 +171,7 @@ void Translations::on_supportedCheck_toggled(bool checked)
|
||||
}
|
||||
ui->translationsTable->blockSignals(true);
|
||||
ui->translationsTable->setRowCount(0);
|
||||
translation = JsonNode(JsonNode::JsonType::DATA_NULL);
|
||||
translation.clear();
|
||||
ui->translationsTable->blockSignals(false);
|
||||
ui->translationsTable->setEnabled(false);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -76,7 +76,7 @@ bool LuaSpellEffect::applicable(Problem & problem, const Mechanics * m) const
|
||||
if(response.getType() != JsonNode::JsonType::DATA_BOOL)
|
||||
{
|
||||
logMod->error("Invalid API response from script %s.", script->getName());
|
||||
logMod->debug(response.toJson(true));
|
||||
logMod->debug(response.toCompactString());
|
||||
return false;
|
||||
}
|
||||
return response.Bool();
|
||||
@ -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);
|
||||
}
|
||||
@ -116,7 +116,7 @@ bool LuaSpellEffect::applicable(Problem & problem, const Mechanics * m, const Ef
|
||||
if(response.getType() != JsonNode::JsonType::DATA_BOOL)
|
||||
{
|
||||
logMod->error("Invalid API response from script %s.", script->getName());
|
||||
logMod->debug(response.toJson(true));
|
||||
logMod->debug(response.toCompactString());
|
||||
return false;
|
||||
}
|
||||
return response.Bool();
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -45,7 +45,7 @@ void GlobalLobbyProcessor::onDisconnected(const std::shared_ptr<INetworkConnecti
|
||||
JsonNode message;
|
||||
message["type"].String() = "leaveGameRoom";
|
||||
message["accountID"].String() = proxy.first;
|
||||
controlConnection->sendPacket(message.toBytes(true));
|
||||
controlConnection->sendPacket(message.toBytes());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -122,7 +122,7 @@ void GlobalLobbyProcessor::onConnectionEstablished(const std::shared_ptr<INetwor
|
||||
toSend["gameRoomID"].String() = owner.uuid;
|
||||
toSend["accountID"] = settings["lobby"]["accountID"];
|
||||
toSend["accountCookie"] = settings["lobby"]["accountCookie"];
|
||||
connection->sendPacket(toSend.toBytes(true));
|
||||
connection->sendPacket(toSend.toBytes());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -137,7 +137,7 @@ void GlobalLobbyProcessor::onConnectionEstablished(const std::shared_ptr<INetwor
|
||||
toSend["gameRoomID"].String() = owner.uuid;
|
||||
toSend["guestAccountID"].String() = guestAccountID;
|
||||
toSend["accountCookie"] = settings["lobby"]["accountCookie"];
|
||||
connection->sendPacket(toSend.toBytes(true));
|
||||
connection->sendPacket(toSend.toBytes());
|
||||
|
||||
proxyConnections[guestAccountID] = connection;
|
||||
owner.onNewConnection(connection);
|
||||
|
@ -165,7 +165,7 @@ void JsonComparer::checkEqualJson(const JsonNode & actual, const JsonNode & expe
|
||||
}
|
||||
else
|
||||
{
|
||||
check(false, "type mismatch. \n expected:\n"+expected.toJson(true)+"\n actual:\n" +actual.toJson(true));
|
||||
check(false, "type mismatch. \n expected:\n"+expected.toCompactString()+"\n actual:\n" +actual.toCompactString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -95,14 +95,14 @@ 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;
|
||||
}
|
||||
|
||||
static void addToArchive(CZipSaver & saver, const JsonNode & data, const std::string & filename)
|
||||
{
|
||||
auto s = data.toJson();
|
||||
auto s = data.toString();
|
||||
std::unique_ptr<COutputStream> stream = saver.addFile(filename);
|
||||
|
||||
if(stream->write((const ui8*)s.c_str(), s.size()) != s.size())
|
||||
|
@ -84,7 +84,7 @@ void MapServiceMock::saveMap(const std::unique_ptr<CMap> & map, boost::filesyste
|
||||
|
||||
void MapServiceMock::addToArchive(CZipSaver & saver, const JsonNode & data, const std::string & filename)
|
||||
{
|
||||
auto s = data.toJson();
|
||||
auto s = data.toString();
|
||||
std::unique_ptr<COutputStream> stream = saver.addFile(filename);
|
||||
|
||||
if(stream->write((const ui8*)s.c_str(), s.size()) != s.size())
|
||||
|
@ -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,8 +84,8 @@ TEST_F(LuaSpellEffectAPITest, DISABLED_ApplicableOnLeftSideOfField)
|
||||
BattleHex hex(2,2);
|
||||
|
||||
JsonNode first;
|
||||
first.Vector().push_back(JsonUtils::intNode(hex.hex));
|
||||
first.Vector().push_back(JsonNode());
|
||||
first.Vector().emplace_back(hex.hex);
|
||||
first.Vector().emplace_back();
|
||||
|
||||
JsonNode targets;
|
||||
targets.Vector().push_back(first);
|
||||
@ -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);
|
||||
|
@ -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().emplace_back(hex1.hex);
|
||||
first.Vector().emplace_back(id1);
|
||||
|
||||
JsonNode second;
|
||||
second.Vector().push_back(JsonUtils::intNode(hex2.hex));
|
||||
second.Vector().push_back(JsonUtils::intNode(-1));
|
||||
second.Vector().emplace_back(hex2.hex);
|
||||
second.Vector().emplace_back(-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().emplace_back(hex1.hex);
|
||||
first.Vector().emplace_back(id1);
|
||||
|
||||
JsonNode targets;
|
||||
targets.Vector().push_back(first);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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";
|
||||
|
@ -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);
|
||||
|
@ -40,7 +40,7 @@ protected:
|
||||
TEST_F(CloneTest, ApplicableToValidTarget)
|
||||
{
|
||||
{
|
||||
JsonNode config(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonNode config;
|
||||
config["maxTier"].Integer() = 7;
|
||||
EffectFixture::setupEffect(config);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user