diff --git a/lib/CCreatureSet.cpp b/lib/CCreatureSet.cpp index bf85fbda6..0247747c0 100644 --- a/lib/CCreatureSet.cpp +++ b/lib/CCreatureSet.cpp @@ -11,6 +11,7 @@ #include "spells/CSpellHandler.h" #include "CHeroHandler.h" #include "IBonusTypeHandler.h" +#include "serializer/JsonSerializeFormat.h" /* * CCreatureSet.cpp, part of VCMI engine @@ -479,27 +480,34 @@ CCreatureSet & CCreatureSet::operator=(const CCreatureSet&cs) void CCreatureSet::armyChanged() { + } -void CCreatureSet::writeJson(JsonNode& json) const +void CCreatureSet::serializeJson(JsonSerializeFormat & handler, const std::string & fieldName) { - for(const auto & p : stacks) + if(handler.saving && stacks.empty()) + return; + JsonNode & json = handler.getCurrent()[fieldName]; + + if(handler.saving) { - JsonNode stack_node; - p.second->writeJson(stack_node); - json.Vector()[p.first.getNum()] = stack_node; + for(const auto & p : stacks) + { + JsonNode stack_node; + p.second->writeJson(stack_node); + json.Vector()[p.first.getNum()] = stack_node; + } } -} - -void CCreatureSet::readJson(const JsonNode& json) -{ - for(size_t idx = 0; idx < json.Vector().size(); idx++) + else { - CStackInstance * new_stack = new CStackInstance(); + for(size_t idx = 0; idx < json.Vector().size(); idx++) + { + CStackInstance * new_stack = new CStackInstance(); - new_stack->readJson(json.Vector()[idx]); + new_stack->readJson(json.Vector()[idx]); - putStack(SlotID(idx), new_stack); + putStack(SlotID(idx), new_stack); + } } } diff --git a/lib/CCreatureSet.h b/lib/CCreatureSet.h index c1a5c8f54..27075e8be 100644 --- a/lib/CCreatureSet.h +++ b/lib/CCreatureSet.h @@ -19,6 +19,7 @@ class CCreature; class CGHeroInstance; class CArmedInstance; class CCreatureArtifactSet; +class JsonSerializeFormat; class DLL_LINKAGE CStackBasicDescriptor { @@ -220,10 +221,7 @@ public: h & stacks & formation; } - - void writeJson(JsonNode & json) const; - - void readJson(const JsonNode & json); + void serializeJson(JsonSerializeFormat & handler, const std::string & fieldName); operator bool() const { diff --git a/lib/mapObjects/CArmedInstance.cpp b/lib/mapObjects/CArmedInstance.cpp index b7c2aafa7..ecb37b01c 100644 --- a/lib/mapObjects/CArmedInstance.cpp +++ b/lib/mapObjects/CArmedInstance.cpp @@ -132,13 +132,3 @@ CBonusSystemNode * CArmedInstance::whatShouldBeAttached() { return this; } - -void CArmedInstance::writeJsonOptions(JsonNode& json) const -{ - CGObjectInstance::writeJsonOptions(json); -} - -void CArmedInstance::readJsonOptions(const JsonNode& json) -{ - CGObjectInstance::readJsonOptions(json); -} diff --git a/lib/mapObjects/CArmedInstance.h b/lib/mapObjects/CArmedInstance.h index bf22a527a..0ebe2abc1 100644 --- a/lib/mapObjects/CArmedInstance.h +++ b/lib/mapObjects/CArmedInstance.h @@ -40,7 +40,4 @@ public: h & static_cast(*this); h & static_cast(*this); } -protected: - void writeJsonOptions(JsonNode & json) const override; - void readJsonOptions(const JsonNode & json) override; }; diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 544dc2f97..5ed39b9f0 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -25,6 +25,7 @@ #include "../CTownHandler.h" #include "../mapping/CMap.h" #include "CGTownInstance.h" +#include "../serializer/JsonSerializeFormat.h" ///helpers static void showInfoDialog(const PlayerColor playerID, const ui32 txtID, const ui16 soundID) @@ -1470,42 +1471,47 @@ bool CGHeroInstance::hasVisions(const CGObjectInstance * target, const int subty return (distance < visionsRange) && (target->pos.z == pos.z); } -void CGHeroInstance::writeJsonOptions(JsonNode& json) const +void CGHeroInstance::serializeJsonOptions(JsonSerializeFormat& handler) { - if(type) + serializeJsonOwner(handler); + + if(handler.saving) { - json["type"].String() = type->identifier; + if(type) + { + handler.serializeString("type", type->identifier); + } + else + { + auto temp = VLC->heroh->heroes[subID]->identifier; + handler.serializeString("type", temp); + } } else { - json["type"].String() = VLC->heroh->heroes[subID]->identifier; + if(ID == Obj::HERO || ID == Obj::PRISON) + { + std::string typeName; + handler.serializeString("type", typeName); + + auto rawId = VLC->modh->identifiers.getIdentifier("core", "hero", typeName); + + if(rawId) + subID = rawId.get(); + else + subID = 0; //fallback to Orrin, throw error instead? + } } + CCreatureSet::serializeJson(handler, "army"); - CGObjectInstance::writeOwner(json); - - CCreatureSet::writeJson(json["army"]); - CArtifactSet::writeJson(json["artifacts"]); - -} - -void CGHeroInstance::readJsonOptions(const JsonNode& json) -{ - if(ID == Obj::HERO || ID == Obj::PRISON) { - auto typeName = json["type"].String(); - - auto rawId = VLC->modh->identifiers.getIdentifier("core", "hero", typeName); - - if(rawId) - subID = rawId.get(); + auto artifacts = handler.enterStruct("artifacts"); + if(handler.saving) + CArtifactSet::writeJson(handler.getCurrent()); else - subID = 0; //fallback to Orrin, throw error instead? + CArtifactSet::readJson(handler.getCurrent()); } - CGObjectInstance::readOwner(json); - - CCreatureSet::readJson(json["army"]); - CArtifactSet::readJson(json["artifacts"]); } bool CGHeroInstance::isMissionCritical() const diff --git a/lib/mapObjects/CGHeroInstance.h b/lib/mapObjects/CGHeroInstance.h index c9781717c..3fd439854 100644 --- a/lib/mapObjects/CGHeroInstance.h +++ b/lib/mapObjects/CGHeroInstance.h @@ -251,8 +251,7 @@ public: std::string getObjectName() const override; protected: void setPropertyDer(ui8 what, ui32 val) override;//synchr - void writeJsonOptions(JsonNode & json) const override; - void readJsonOptions(const JsonNode & json) override; + void serializeJsonOptions(JsonSerializeFormat & handler) override; private: void levelUpAutomatically(); diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index dfa3ba2f1..808416670 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -19,6 +19,7 @@ #include "../CGameState.h" #include "../mapping/CMapDefines.h" #include "../CPlayerState.h" +#include "../serializer/JsonSerializeFormat.h" std::vector CGTownInstance::merchantArtifacts; std::vector CGTownInstance::universitySkills; @@ -314,18 +315,11 @@ void CGDwelling::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) } } -void CGDwelling::writeJsonOptions(JsonNode& json) const +void CGDwelling::serializeJsonOptions(JsonSerializeFormat & handler) { - //todo:CGDwelling::writeJsonOptions + //todo: CGDwelling::serializeJsonOptions if(ID != Obj::WAR_MACHINE_FACTORY && ID != Obj::REFUGEE_CAMP) - CGObjectInstance::writeOwner(json); -} - -void CGDwelling::readJsonOptions(const JsonNode& json) -{ - //todo:CGDwelling::readJsonOptions - if(ID != Obj::WAR_MACHINE_FACTORY && ID != Obj::REFUGEE_CAMP) - CGObjectInstance::readOwner(json); + serializeJsonOwner(handler); } int CGTownInstance::getSightRadius() const //returns sight distance @@ -1129,6 +1123,14 @@ void CGTownInstance::battleFinished(const CGHeroInstance *hero, const BattleResu } } +void CGTownInstance::serializeJsonOptions(JsonSerializeFormat& handler) +{ + CGObjectInstance::serializeJsonOwner(handler); + CCreatureSet::serializeJson(handler, "army"); + + //todo: CGTownInstance::serializeJsonOptions +} + COPWBonus::COPWBonus (BuildingID index, CGTownInstance *TOWN) { ID = index; diff --git a/lib/mapObjects/CGTownInstance.h b/lib/mapObjects/CGTownInstance.h index 70ec532fb..9b31fd245 100644 --- a/lib/mapObjects/CGTownInstance.h +++ b/lib/mapObjects/CGTownInstance.h @@ -53,8 +53,7 @@ public: TCreaturesSet creatures; //creatures[level] -> protected: - void writeJsonOptions(JsonNode & json) const override; - void readJsonOptions(const JsonNode & json) override; + void serializeJsonOptions(JsonSerializeFormat & handler) override; private: void initObj() override; @@ -256,4 +255,5 @@ public: std::string getObjectName() const override; protected: void setPropertyDer(ui8 what, ui32 val) override; + void serializeJsonOptions(JsonSerializeFormat & handler) override; }; diff --git a/lib/mapObjects/CObjectHandler.cpp b/lib/mapObjects/CObjectHandler.cpp index a0d9d9d87..7742eccb2 100644 --- a/lib/mapObjects/CObjectHandler.cpp +++ b/lib/mapObjects/CObjectHandler.cpp @@ -24,6 +24,8 @@ #include "CObjectClassesHandler.h" #include "CGTownInstance.h" +#include "../serializer/JsonSerializeFormat.h" + IGameCallback * IObjectInterface::cb = nullptr; ///helpers @@ -331,64 +333,70 @@ bool CGObjectInstance::passableFor(PlayerColor color) const return false; } -void CGObjectInstance::writeJson(JsonNode & json) const +void CGObjectInstance::serializeJson(JsonSerializeFormat & handler) { - logGlobal->debugStream() <<"Save: [" << pos << "] " << id << " " << ID << " " << subID << " " << typeName << " " << subTypeName; - - json.setType(JsonNode::DATA_STRUCT); - json["type"].String() = typeName; - json["subType"].String() = subTypeName; - json["x"].Float() = pos.x; - json["y"].Float() = pos.y; - json["l"].Float() = pos.z; - - appearance.writeJson(json["template"], false); - writeJsonOptions(json["options"]); -} - -void CGObjectInstance::readJson(const JsonNode & json) -{ - if(json.getType() != JsonNode::DATA_STRUCT) + if(handler.saving) { - logGlobal->error("Invalid object instance data"); - return; + handler.serializeString("type", typeName); + handler.serializeString("subType", subTypeName); } - pos.x = json["x"].Float(); - pos.y = json["y"].Float(); - pos.z = json["l"].Float(); - appearance.readJson(json["template"], false); + handler.serializeNumeric("x", pos.x); + handler.serializeNumeric("y", pos.y); + handler.serializeNumeric("l", pos.z); - readJsonOptions(json["options"]); -} - -void CGObjectInstance::writeJsonOptions(JsonNode & json) const -{ - json.setType(JsonNode::DATA_STRUCT); -} - -void CGObjectInstance::readJsonOptions(const JsonNode & json) -{ -} - -void CGObjectInstance::writeOwner(JsonNode & json) const -{ - if(tempOwner.isValidPlayer()) + if(handler.saving) { - json["owner"].String() = GameConstants::PLAYER_COLOR_NAMES[tempOwner.getNum()]; + appearance.writeJson(handler.getCurrent()["template"], false); + } + else + { + appearance.readJson(handler.getCurrent()["template"], false); + } + + { + auto options = handler.enterStruct("options"); + serializeJsonOptions(handler); + } + + if(handler.saving && handler.getCurrent()["options"].isNull()) + { + handler.getCurrent().Struct().erase("options"); } } -void CGObjectInstance::readOwner(const JsonNode & json) +void CGObjectInstance::serializeJsonOptions(JsonSerializeFormat & handler) { - tempOwner = PlayerColor::NEUTRAL;//this method assumes that object is ownable - if(json["owner"].getType() == JsonNode::DATA_STRING) + +} + +void CGObjectInstance::serializeJsonOwner(JsonSerializeFormat & handler) +{ + std::string temp; + + //todo: use enum serialize + if(handler.saving) { - auto rawOwner = vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, json["owner"].String()); - if(rawOwner >=0) - tempOwner = PlayerColor(rawOwner); - else - logGlobal->errorStream() << "Invalid owner :" << json["owner"].String(); + if(tempOwner.isValidPlayer()) + { + temp = GameConstants::PLAYER_COLOR_NAMES[tempOwner.getNum()]; + handler.serializeString("owner", temp); + } + } + else + { + tempOwner = PlayerColor::NEUTRAL;//this method assumes that object is ownable + + handler.serializeString("owner", temp); + + if(temp != "") + { + auto rawOwner = vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, temp); + if(rawOwner >=0) + tempOwner = PlayerColor(rawOwner); + else + logGlobal->errorStream() << "Invalid owner :" << temp; + } } } diff --git a/lib/mapObjects/CObjectHandler.h b/lib/mapObjects/CObjectHandler.h index 12fe7eda6..d417f4763 100644 --- a/lib/mapObjects/CObjectHandler.h +++ b/lib/mapObjects/CObjectHandler.h @@ -21,6 +21,7 @@ class IGameCallback; class CGObjectInstance; struct MetaString; struct BattleResult; +class JsonSerializeFormat; // This one teleport-specific, but has to be available everywhere in callbacks and netpacks // For now it's will be there till teleports code refactored and moved into own file @@ -186,10 +187,7 @@ public: } ///Entry point of Json serialization - void writeJson(JsonNode & json) const; - - ///Entry point of Json de-serialization - void readJson(const JsonNode & json); + void serializeJson(JsonSerializeFormat & handler); protected: /// virtual method that allows synchronously update object state on server and all clients @@ -198,16 +196,11 @@ protected: /// Gives dummy bonus from this object to hero. Can be used to track visited state void giveDummyBonus(ObjectInstanceID heroID, ui8 duration = Bonus::ONE_DAY) const; - ///Saves object-type specific options - ///(!) do not forget to call inherited method first when overriding - virtual void writeJsonOptions(JsonNode & json) const; + ///Serialize object-type specific options + virtual void serializeJsonOptions(JsonSerializeFormat & handler); - ///Loads object-type specific options - ///(!) do not forget to call inherited method first when overriding - virtual void readJsonOptions(const JsonNode & json); + void serializeJsonOwner(JsonSerializeFormat & handler); - void writeOwner(JsonNode & json) const; - void readOwner(const JsonNode & json); private: mutable std::string stringId;/// > CGMagi::eyelist; ui8 CGObelisk::obeliskCount = 0; //how many obelisks are on map @@ -593,59 +594,60 @@ void CGCreature::giveReward(const CGHeroInstance * h) const } } -static const std::string CHARACTER_JSON [] = +static const std::vector CHARACTER_JSON = { "compliant", "friendly", "aggressive", "hostile", "savage" }; -void CGCreature::writeJsonOptions(JsonNode& json) const +void CGCreature::serializeJsonOptions(JsonSerializeFormat & handler) { - assert(vstd::iswithin(character, 0, 4)); - json["character"].String() = CHARACTER_JSON[character]; + handler.serializeNumericEnum("character", CHARACTER_JSON, (si8)0, character); - if(hasStackAtSlot(SlotID(0))) + if(handler.saving) { - const auto & sta = getStack(SlotID(0)); - json["amount"].Float() = sta.count; + if(hasStackAtSlot(SlotID(0))) + { + si32 amount = getStack(SlotID(0)).count; + handler.serializeNumeric("amount", amount); + } + + if(resources.nonZero()) + { + for(size_t idx = 0; idx < resources.size(); idx++) + handler.getCurrent()["rewardResources"][GameConstants::RESOURCE_NAMES[idx]].Float() = resources[idx]; + } + + auto tmp = (gainedArtifact == ArtifactID(ArtifactID::NONE) ? "" : gainedArtifact.toArtifact()->identifier); + handler.serializeString("rewardArtifact", tmp); } - - json["noGrowing"].Bool() = notGrowingTeam; - json["neverFlees"].Bool() = neverFlees; - json["rewardMessage"].String() = message; - json["rewardArtifact"].String() = (gainedArtifact == ArtifactID(ArtifactID::NONE) ? "" : gainedArtifact.toArtifact()->identifier); - - if(resources.nonZero()) + else { - for(size_t idx = 0; idx < resources.size(); idx++) - json["rewardResources"][GameConstants::RESOURCE_NAMES[idx]].Float() = resources[idx]; + si32 amount = 0; + handler.serializeNumeric("amount", amount); + auto hlp = new CStackInstance(); + hlp->count = amount; + //type will be set during initialization + putStack(SlotID(0), hlp); + { + TResources tmp(handler.getCurrent()["rewardResources"]); + std::swap(tmp,resources); + } + { + gainedArtifact = ArtifactID(ArtifactID::NONE); + std::string tmp; + handler.serializeString("rewardArtifact", tmp); + + if(tmp != "") + { + auto artid = VLC->modh->identifiers.getIdentifier("core", "artifact", tmp); + if(artid) + gainedArtifact = ArtifactID(artid.get()); + } + } } -} - -void CGCreature::readJsonOptions(const JsonNode& json) -{ - character = vstd::find_pos(CHARACTER_JSON,json["character"].String()); - vstd::amin(character, 0); - - auto hlp = new CStackInstance(); - hlp->count = json["amount"].Float(); - //type will be set during initialization - putStack(SlotID(0), hlp); - - notGrowingTeam = json["noGrowing"].Bool(); - neverFlees = json["neverFlees"].Bool(); - message = json["rewardMessage"].String(); - - gainedArtifact = ArtifactID(ArtifactID::NONE); - - if(json["rewardArtifact"].String() != "") - { - auto artid = VLC->modh->identifiers.getIdentifier("core", "artifact", json["rewardArtifact"].String()); - if(artid) - gainedArtifact = ArtifactID(artid.get()); - } - - TResources tmp(json["rewardResources"]); - std::swap(tmp,resources); + handler.serializeBool("noGrowing", notGrowingTeam); + handler.serializeBool("neverFlees", neverFlees); + handler.serializeString("rewardMessage", message); } //CGMine @@ -790,71 +792,63 @@ void CGMine::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) con cb->startBattleI(hero, this); } -void CGMine::writeJsonOptions(JsonNode & json) const +void CGMine::serializeJsonOptions(JsonSerializeFormat & handler) { - CCreatureSet::writeJson(json["army"]); + CCreatureSet::serializeJson(handler, "army"); if(isAbandoned()) { - JsonNode & node = json["possibleResources"]; + auto possibleResources = handler.enterStruct("possibleResources"); - for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++) - if(tempOwner.getNum() & 1< possibleResources; - - if(node.Vector().size() == 0) + if(handler.saving) { - //assume all allowed - for(int i = (int)Res::WOOD; i < (int) Res::GOLD; i++) - possibleResources.insert(i); + for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++) + if(tempOwner.getNum() & 1<>(); + std::set possibleResources; - for(const std::string & s : names) + if(node.Vector().size() == 0) { - int raw_res = vstd::find_pos(GameConstants::RESOURCE_NAMES, s); - if(raw_res < 0) - logGlobal->errorStream() << "Invalid resource name: "+s; - else - possibleResources.insert(raw_res); + //assume all allowed + for(int i = (int)Res::WOOD; i < (int) Res::GOLD; i++) + possibleResources.insert(i); } + else + { + auto names = node.convertTo>(); - int tmp = 0; + for(const std::string & s : names) + { + int raw_res = vstd::find_pos(GameConstants::RESOURCE_NAMES, s); + if(raw_res < 0) + logGlobal->errorStream() << "Invalid resource name: "+s; + else + possibleResources.insert(raw_res); + } - for(int r : possibleResources) - tmp |= (1<generaltexth->restypes[subID]; @@ -939,18 +933,11 @@ void CGResource::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) cb->startBattleI(hero, this); } -void CGResource::writeJsonOptions(JsonNode& json) const +void CGResource::serializeJsonOptions(JsonSerializeFormat & handler) { - CCreatureSet::writeJson(json["guards"]); - json["amount"].Float() = amount; - json["guardMessage"].String() = message; -} - -void CGResource::readJsonOptions(const JsonNode& json) -{ - CCreatureSet::readJson(json["guards"]); - amount = json["amount"].Float(); - message = json["guardMessage"].String(); + CCreatureSet::serializeJson(handler, "guards"); + handler.serializeNumeric("amount", amount); + handler.serializeString("guardMessage", message); } CGTeleport::CGTeleport() : @@ -1439,25 +1426,21 @@ void CGArtifact::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) cb->startBattleI(hero, this); } -void CGArtifact::writeJsonOptions(JsonNode& json) const +void CGArtifact::serializeJsonOptions(JsonSerializeFormat& handler) { - CCreatureSet::writeJson(json["guards"]); - json["guardMessage"].String() = message; - if(ID == Obj::SPELL_SCROLL) + handler.serializeString("guardMessage", message); + CCreatureSet::serializeJson(handler, "guards"); + + if(handler.saving && ID == Obj::SPELL_SCROLL) { const Bonus * b = storedArtifact->getBonusLocalFirst(Selector::type(Bonus::SPELL)); SpellID spellId(b->subtype); - json["spell"].String() = SpellID(b->subtype).toSpell()->identifier; + std::string spell = SpellID(b->subtype).toSpell()->identifier; + handler.serializeString("spell", spell); } } -void CGArtifact::readJsonOptions(const JsonNode& json) -{ - CCreatureSet::readJson(json["guards"]); - message = json["guardMessage"].String(); -} - void CGWitchHut::initObj() { if (allowedAbilities.empty()) //this can happen for RMG. regular maps load abilities from map file @@ -1515,17 +1498,11 @@ std::string CGWitchHut::getHoverText(const CGHeroInstance * hero) const return hoverName; } -void CGWitchHut::writeJsonOptions(JsonNode& json) const +void CGWitchHut::serializeJsonOptions(JsonSerializeFormat & handler) { - + //todo:CGWitchHut::serializeJsonOptions } -void CGWitchHut::readJsonOptions(const JsonNode& json) -{ - -} - - void CGMagicWell::onHeroVisit( const CGHeroInstance * h ) const { int message; @@ -1665,23 +1642,9 @@ std::string CGShrine::getHoverText(const CGHeroInstance * hero) const return hoverName; } -void CGShrine::writeJsonOptions(JsonNode& json) const +void CGShrine::serializeJsonOptions(JsonSerializeFormat& handler) { - if(spell != SpellID::NONE) - { - json["spell"].String() = spell.toSpell()->identifier; - } -} - -void CGShrine::readJsonOptions(const JsonNode& json) -{ - spell = SpellID::NONE; - if(json["spell"].String() != "") - { - auto raw = VLC->modh->identifiers.getIdentifier("core", "spell",json["spell"].String()); - if(raw) - spell = SpellID(raw.get()); - } + handler.serializeId("spell", &CSpellHandler::decodeSpell, &CSpellHandler::encodeSpell, SpellID(SpellID::NONE), spell); } void CGSignBottle::initObj() @@ -1710,14 +1673,9 @@ void CGSignBottle::onHeroVisit( const CGHeroInstance * h ) const cb->removeObject(this); } -void CGSignBottle::writeJsonOptions(JsonNode& json) const +void CGSignBottle::serializeJsonOptions(JsonSerializeFormat& handler) { - json["text"].String() = message; -} - -void CGSignBottle::readJsonOptions(const JsonNode& json) -{ - message = json["text"].String(); + handler.serializeString("text", message); } void CGScholar::onHeroVisit( const CGHeroInstance * h ) const @@ -1793,52 +1751,55 @@ void CGScholar::initObj() } } -void CGScholar::writeJsonOptions(JsonNode& json) const +void CGScholar::serializeJsonOptions(JsonSerializeFormat & handler) { - switch(bonusType) + JsonNode& json = handler.getCurrent(); + if(handler.saving) { - case PRIM_SKILL: - json["rewardPrimSkill"].String() = PrimarySkill::names[bonusID]; - break; - case SECONDARY_SKILL: - json["rewardSkill"].String() = NSecondarySkill::names[bonusID]; - break; - case SPELL: - json["rewardSpell"].String() = VLC->spellh->objects.at(bonusID)->identifier; - break; - case RANDOM: - break; - } -} - -void CGScholar::readJsonOptions(const JsonNode& json) -{ - bonusType = RANDOM; - if(json["rewardPrimSkill"].String() != "") - { - auto raw = VLC->modh->identifiers.getIdentifier("core", "primSkill", json["rewardPrimSkill"].String()); - if(raw) + switch(bonusType) { - bonusType = PRIM_SKILL; - bonusID = raw.get(); + case PRIM_SKILL: + json["rewardPrimSkill"].String() = PrimarySkill::names[bonusID]; + break; + case SECONDARY_SKILL: + json["rewardSkill"].String() = NSecondarySkill::names[bonusID]; + break; + case SPELL: + json["rewardSpell"].String() = VLC->spellh->objects.at(bonusID)->identifier; + break; + case RANDOM: + break; } } - else if(json["rewardSkill"].String() != "") + else { - auto raw = VLC->modh->identifiers.getIdentifier("core", "skill", json["rewardSkill"].String()); - if(raw) + bonusType = RANDOM; + if(json["rewardPrimSkill"].String() != "") { - bonusType = SECONDARY_SKILL; - bonusID = raw.get(); + auto raw = VLC->modh->identifiers.getIdentifier("core", "primSkill", json["rewardPrimSkill"].String()); + if(raw) + { + bonusType = PRIM_SKILL; + bonusID = raw.get(); + } } - } - else if(json["rewardSpell"].String() != "") - { - auto raw = VLC->modh->identifiers.getIdentifier("core", "spell", json["rewardSpell"].String()); - if(raw) + else if(json["rewardSkill"].String() != "") { - bonusType = SPELL; - bonusID = raw.get(); + auto raw = VLC->modh->identifiers.getIdentifier("core", "skill", json["rewardSkill"].String()); + if(raw) + { + bonusType = SECONDARY_SKILL; + bonusID = raw.get(); + } + } + else if(json["rewardSpell"].String() != "") + { + auto raw = VLC->modh->identifiers.getIdentifier("core", "spell", json["rewardSpell"].String()); + if(raw) + { + bonusType = SPELL; + bonusID = raw.get(); + } } } } @@ -1879,18 +1840,11 @@ void CGGarrison::battleFinished(const CGHeroInstance *hero, const BattleResult & onHeroVisit(hero); } -void CGGarrison::writeJsonOptions(JsonNode& json) const +void CGGarrison::serializeJsonOptions(JsonSerializeFormat& handler) { - CCreatureSet::writeJson(json["army"]); - CGObjectInstance::writeOwner(json); - json["removableUnits"].Bool() = removableUnits; -} - -void CGGarrison::readJsonOptions(const JsonNode& json) -{ - CCreatureSet::readJson(json["army"]); - CGObjectInstance::readOwner(json); - removableUnits = json["removableUnits"].Bool(); + handler.serializeBool("removableUnits", removableUnits); + serializeJsonOwner(handler); + CCreatureSet::serializeJson(handler, "army"); } void CGMagi::initObj() @@ -2030,14 +1984,9 @@ void CGShipyard::onHeroVisit( const CGHeroInstance * h ) const } } -void CGShipyard::writeJsonOptions(JsonNode& json) const +void CGShipyard::serializeJsonOptions(JsonSerializeFormat& handler) { - CGObjectInstance::writeOwner(json); -} - -void CGShipyard::readJsonOptions(const JsonNode& json) -{ - CGObjectInstance::readOwner(json); + serializeJsonOwner(handler); } void CCartographer::onHeroVisit( const CGHeroInstance * h ) const @@ -2222,12 +2171,7 @@ void CGLighthouse::giveBonusTo( PlayerColor player ) const cb->sendAndApply(&gb); } -void CGLighthouse::writeJsonOptions(JsonNode& json) const +void CGLighthouse::serializeJsonOptions(JsonSerializeFormat& handler) { - CGObjectInstance::writeOwner(json); -} - -void CGLighthouse::readJsonOptions(const JsonNode& json) -{ - CGObjectInstance::readOwner(json); + serializeJsonOwner(handler); } diff --git a/lib/mapObjects/MiscObjects.h b/lib/mapObjects/MiscObjects.h index 22f9695ee..582d3db9e 100644 --- a/lib/mapObjects/MiscObjects.h +++ b/lib/mapObjects/MiscObjects.h @@ -86,11 +86,9 @@ public: } protected: void setPropertyDer(ui8 what, ui32 val) override; + void serializeJsonOptions(JsonSerializeFormat & handler) override; - void writeJsonOptions(JsonNode & json) const override; - void readJsonOptions(const JsonNode & json) override; private: - void fight(const CGHeroInstance *h) const; void flee( const CGHeroInstance * h ) const; void fleeDecision(const CGHeroInstance *h, ui32 pursue) const; @@ -101,7 +99,6 @@ private: }; - class DLL_LINKAGE CGSignBottle : public CGObjectInstance //signs and ocean bottles { public: @@ -116,8 +113,7 @@ public: h & message; } protected: - void writeJsonOptions(JsonNode & json) const override; - void readJsonOptions(const JsonNode & json) override; + void serializeJsonOptions(JsonSerializeFormat & handler) override; }; class DLL_LINKAGE CGWitchHut : public CPlayersVisited @@ -136,8 +132,7 @@ public: h & allowedAbilities & ability; } protected: - void writeJsonOptions(JsonNode & json) const override; - void readJsonOptions(const JsonNode & json) override; + void serializeJsonOptions(JsonSerializeFormat & handler) override; }; class DLL_LINKAGE CGScholar : public CGObjectInstance @@ -156,8 +151,7 @@ public: h & bonusType & bonusID; } protected: - void writeJsonOptions(JsonNode & json) const override; - void readJsonOptions(const JsonNode & json) override; + void serializeJsonOptions(JsonSerializeFormat & handler) override; }; class DLL_LINKAGE CGGarrison : public CArmedInstance @@ -175,8 +169,7 @@ public: h & removableUnits; } protected: - void writeJsonOptions(JsonNode & json) const override; - void readJsonOptions(const JsonNode & json) override; + void serializeJsonOptions(JsonSerializeFormat & handler) override; }; class DLL_LINKAGE CGArtifact : public CArmedInstance @@ -202,8 +195,7 @@ public: h & message & storedArtifact; } protected: - void writeJsonOptions(JsonNode & json) const override; - void readJsonOptions(const JsonNode & json) override; + void serializeJsonOptions(JsonSerializeFormat & handler) override; }; class DLL_LINKAGE CGResource : public CArmedInstance @@ -227,8 +219,7 @@ public: h & amount & message; } protected: - void writeJsonOptions(JsonNode & json) const override; - void readJsonOptions(const JsonNode & json) override; + void serializeJsonOptions(JsonSerializeFormat & handler) override; }; class DLL_LINKAGE CGShrine : public CPlayersVisited @@ -246,8 +237,7 @@ public: h & spell; } protected: - void writeJsonOptions(JsonNode & json) const override; - void readJsonOptions(const JsonNode & json) override; + void serializeJsonOptions(JsonSerializeFormat & handler) override; }; class DLL_LINKAGE CGMine : public CArmedInstance @@ -277,8 +267,7 @@ public: } ui32 defaultResProduction(); protected: - void writeJsonOptions(JsonNode & json) const override; - void readJsonOptions(const JsonNode & json) override; + void serializeJsonOptions(JsonSerializeFormat & handler) override; }; struct DLL_LINKAGE TeleportChannel @@ -444,8 +433,7 @@ public: h & static_cast(*this); } protected: - void writeJsonOptions(JsonNode & json) const override; - void readJsonOptions(const JsonNode & json) override; + void serializeJsonOptions(JsonSerializeFormat & handler) override; }; class DLL_LINKAGE CGMagi : public CGObjectInstance @@ -462,8 +450,6 @@ public: } }; - - class DLL_LINKAGE CCartographer : public CPlayersVisited { ///behaviour varies depending on surface and floor @@ -515,6 +501,5 @@ public: } void giveBonusTo( PlayerColor player ) const; protected: - void writeJsonOptions(JsonNode & json) const override; - void readJsonOptions(const JsonNode & json) override; + void serializeJsonOptions(JsonSerializeFormat & handler) override; }; diff --git a/lib/mapping/MapFormatJson.cpp b/lib/mapping/MapFormatJson.cpp index 22d508db0..17f8680f5 100644 --- a/lib/mapping/MapFormatJson.cpp +++ b/lib/mapping/MapFormatJson.cpp @@ -525,7 +525,7 @@ std::unique_ptr CMapLoaderJson::loadMapHeader() return std::move(result); } -const JsonNode CMapLoaderJson::getFromArchive(const std::string & archiveFilename) +JsonNode CMapLoaderJson::getFromArchive(const std::string & archiveFilename) { ResourceID resource(archiveFilename, EResType::TEXT); @@ -747,7 +747,7 @@ void CMapLoaderJson::readTerrain() } -CMapLoaderJson::MapObjectLoader::MapObjectLoader(CMapLoaderJson * _owner, const JsonMap::value_type& json): +CMapLoaderJson::MapObjectLoader::MapObjectLoader(CMapLoaderJson * _owner, JsonMap::value_type& json): owner(_owner), instance(nullptr),id(-1), jsonKey(json.first), configuration(json.second), internalId(extractNumber(jsonKey, '_')) { @@ -797,7 +797,9 @@ void CMapLoaderJson::MapObjectLoader::configure() if(nullptr == instance) return; - instance->readJson(configuration); + JsonDeserializer handler(configuration); + + instance->serializeJson(handler); if(instance->ID == Obj::TOWN) { @@ -841,10 +843,10 @@ void CMapLoaderJson::readObjects() std::vector> loaders;//todo: optimize MapObjectLoader memory layout - const JsonNode data = getFromArchive(OBJECTS_FILE_NAME); + JsonNode data = getFromArchive(OBJECTS_FILE_NAME); //get raw data - for(const auto & p : data.Struct()) + for(auto & p : data.Struct()) loaders.push_back(vstd::make_unique(this, p)); auto sortInfos = [](const std::unique_ptr & lhs, const std::unique_ptr & rhs) -> bool @@ -993,8 +995,14 @@ void CMapSaverJson::writeObjects() { JsonNode data(JsonNode::DATA_STRUCT); - for(const CGObjectInstance * obj : map->objects) - obj->writeJson(data[obj->getStringId()]); + JsonSerializer handler(data); + + for(CGObjectInstance * obj : map->objects) + { + auto temp = handler.enterStruct(obj->getStringId()); + + obj->serializeJson(handler); + } if(map->grailPos.valid()) { @@ -1010,7 +1018,6 @@ void CMapSaverJson::writeObjects() std::string grailId = boost::str(boost::format("grail_%d") % map->objects.size()); data[grailId] = grail; - } addToArchive(data, OBJECTS_FILE_NAME); diff --git a/lib/mapping/MapFormatJson.h b/lib/mapping/MapFormatJson.h index 4e8f185dc..17d8b2a31 100644 --- a/lib/mapping/MapFormatJson.h +++ b/lib/mapping/MapFormatJson.h @@ -159,12 +159,12 @@ private: struct MapObjectLoader { - MapObjectLoader(CMapLoaderJson * _owner, const JsonMap::value_type & json); + MapObjectLoader(CMapLoaderJson * _owner, JsonMap::value_type & json); CMapLoaderJson * owner; CGObjectInstance * instance; ObjectInstanceID id; std::string jsonKey;//full id defined by map creator - const JsonNode & configuration; + JsonNode & configuration; si32 internalId;//unique part of id defined by map creator (also = quest identifier) ///constructs object (without configuration) void construct(); @@ -197,7 +197,7 @@ private: */ void readObjects(); - const JsonNode getFromArchive(const std::string & archiveFilename); + JsonNode getFromArchive(const std::string & archiveFilename); CInputStream * buffer; std::shared_ptr ioApi; diff --git a/lib/serializer/JsonDeserializer.cpp b/lib/serializer/JsonDeserializer.cpp index 518758129..72af19bb0 100644 --- a/lib/serializer/JsonDeserializer.cpp +++ b/lib/serializer/JsonDeserializer.cpp @@ -48,6 +48,24 @@ void JsonDeserializer::serializeIntEnum(const std::string & fieldName, const std value = rawValue; } +void JsonDeserializer::serializeIntId(const std::string & fieldName, const TDecoder & decoder, const TEncoder & encoder, const si32 defaultValue, si32 & value) +{ + std::string identifier; + serializeString(fieldName, identifier); + + if(identifier == "") + { + value = defaultValue; + return; + } + + si32 rawId = decoder(identifier); + if(rawId >= 0) + value = rawId; + else + value = defaultValue; +} + void JsonDeserializer::serializeLIC(const std::string & fieldName, const TDecoder & decoder, const TEncoder & encoder, const std::vector & standard, std::vector & value) { const JsonNode & field = current->operator[](fieldName); diff --git a/lib/serializer/JsonDeserializer.h b/lib/serializer/JsonDeserializer.h index b05c9582a..2130b3812 100644 --- a/lib/serializer/JsonDeserializer.h +++ b/lib/serializer/JsonDeserializer.h @@ -27,4 +27,5 @@ public: protected: void serializeFloat(const std::string & fieldName, double & value) override; void serializeIntEnum(const std::string & fieldName, const std::vector & enumMap, const si32 defaultValue, si32 & value) override; + void serializeIntId(const std::string & fieldName, const TDecoder & decoder, const TEncoder & encoder, const si32 defaultValue, si32 & value) override; }; diff --git a/lib/serializer/JsonSerializeFormat.h b/lib/serializer/JsonSerializeFormat.h index 6b84308de..424f2d9aa 100644 --- a/lib/serializer/JsonSerializeFormat.h +++ b/lib/serializer/JsonSerializeFormat.h @@ -98,6 +98,16 @@ public: virtual void serializeString(const std::string & fieldName, std::string & value) = 0; + template + void serializeId(const std::string & fieldName, const TDecoder & decoder, const TEncoder & encoder, const T & defaultValue, T & value) + { + const si32 tempDefault = defaultValue.num; + si32 tempValue = value.num; + serializeIntId(fieldName, decoder, encoder, tempDefault, tempValue); + if(!saving) + value = T(tempValue); + } + protected: JsonNode * root; JsonNode * current; @@ -107,6 +117,8 @@ protected: virtual void serializeFloat(const std::string & fieldName, double & value) = 0; virtual void serializeIntEnum(const std::string & fieldName, const std::vector & enumMap, const si32 defaultValue, si32 & value) = 0; + + virtual void serializeIntId(const std::string & fieldName, const TDecoder & decoder, const TEncoder & encoder, const si32 defaultValue, si32 & value) = 0; private: friend class JsonStructSerializer; }; diff --git a/lib/serializer/JsonSerializer.cpp b/lib/serializer/JsonSerializer.cpp index 8fff1f7af..e0b339487 100644 --- a/lib/serializer/JsonSerializer.cpp +++ b/lib/serializer/JsonSerializer.cpp @@ -40,6 +40,15 @@ void JsonSerializer::serializeIntEnum(const std::string & fieldName, const std:: current->operator[](fieldName).String() = enumMap.at(value); } +void JsonSerializer::serializeIntId(const std::string & fieldName, const TDecoder & decoder, const TEncoder & encoder, const si32 defaultValue, si32& value) +{ + if(defaultValue == value) + return; + + std::string identifier = encoder(value); + serializeString(fieldName, identifier); +} + void JsonSerializer::serializeLIC(const std::string & fieldName, const TDecoder & decoder, const TEncoder & encoder, const std::vector & standard, std::vector & value) { assert(standard.size() == value.size()); diff --git a/lib/serializer/JsonSerializer.h b/lib/serializer/JsonSerializer.h index 6eca2cce0..ad19fe782 100644 --- a/lib/serializer/JsonSerializer.h +++ b/lib/serializer/JsonSerializer.h @@ -27,4 +27,5 @@ public: protected: void serializeFloat(const std::string & fieldName, double & value) override; void serializeIntEnum(const std::string & fieldName, const std::vector & enumMap, const si32 defaultValue, si32 & value) override; + void serializeIntId(const std::string & fieldName, const TDecoder & decoder, const TEncoder & encoder, const si32 defaultValue, si32 & value) override; };