1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Advance map header serialization

This commit is contained in:
AlexVinS 2016-02-21 20:58:09 +03:00
parent b6103167f7
commit 53b5587c2e
16 changed files with 230 additions and 75 deletions

View File

@ -203,7 +203,7 @@ std::vector<JsonNode> CArtHandler::loadLegacyData(size_t dataSize)
void CArtHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
{
auto object = loadFromJson(data, name);
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
object->id = ArtifactID(artifacts.size());
object->iconIndex = object->id + 5;
@ -231,12 +231,12 @@ void CArtHandler::loadObject(std::string scope, std::string name, const JsonNode
VLC->objtypeh->removeSubObject(Obj::ARTIFACT, object->id);
});
registerObject(scope, "artifact", object->identifier, object->id);
registerObject(scope, "artifact", name, object->id);
}
void CArtHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
{
auto object = loadFromJson(data, name);
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
object->id = ArtifactID(index);
object->iconIndex = object->id;
@ -264,7 +264,7 @@ void CArtHandler::loadObject(std::string scope, std::string name, const JsonNode
if (VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, object->id)->getTemplates().empty())
VLC->objtypeh->removeSubObject(Obj::ARTIFACT, object->id);
});
registerObject(scope, "artifact", object->identifier, object->id);
registerObject(scope, "artifact", name, object->id);
}
CArtifact * CArtHandler::loadFromJson(const JsonNode & node, const std::string & identifier)
@ -674,7 +674,7 @@ std::vector<bool> CArtHandler::getDefaultAllowed() const
std::vector<bool> allowedArtifacts;
allowedArtifacts.resize(127, true);
allowedArtifacts.resize(141, false);
allowedArtifacts.resize(GameConstants::ARTIFACTS_QUANTITY, true);
allowedArtifacts.resize(artifacts.size(), true);
return allowedArtifacts;
}
@ -742,6 +742,20 @@ void CArtHandler::afterLoadFinalization()
CBonusSystemNode::treeHasChanged();
}
si32 CArtHandler::decodeArfifact(const std::string& identifier)
{
auto rawId = VLC->modh->identifiers.getIdentifier("core", "artifact", identifier);
if(rawId)
return rawId.get();
else
return -1;
}
std::string CArtHandler::encodeArtifact(const si32 index)
{
return VLC->arth->artifacts[index]->identifier;
}
CArtifactInstance::CArtifactInstance()
{
init();

View File

@ -255,6 +255,12 @@ public:
std::vector<bool> getDefaultAllowed() const override;
///json serialization helper
static si32 decodeArfifact(const std::string & identifier);
///json serialization helper
static std::string encodeArtifact(const si32 index);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & artifacts & allowedArtifacts & treasures & minors & majors & relics

View File

@ -368,7 +368,7 @@ std::vector<JsonNode> CCreatureHandler::loadLegacyData(size_t dataSize)
void CCreatureHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
{
auto object = loadFromJson(data, name);
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
object->setId(CreatureID(creatures.size()));
object->iconIndex = object->idNumber + 2;
@ -402,7 +402,7 @@ void CCreatureHandler::loadObject(std::string scope, std::string name, const Jso
void CCreatureHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
{
auto object = loadFromJson(data, name);
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
object->setId(CreatureID(index));
object->iconIndex = object->idNumber + 2;

View File

@ -192,7 +192,7 @@ std::vector<JsonNode> CHeroClassHandler::loadLegacyData(size_t dataSize)
void CHeroClassHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
{
auto object = loadFromJson(data, name);
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
object->id = heroClasses.size();
heroClasses.push_back(object);
@ -205,19 +205,12 @@ void CHeroClassHandler::loadObject(std::string scope, std::string name, const Js
VLC->objtypeh->loadSubObject(name, classConf, index, object->id);
});
// VLC->modh->identifiers.requestIdentifier(scope, "object", "prison", [=](si32 index)
// {
// JsonNode conf;
// conf.setMeta(scope);
// VLC->objtypeh->loadSubObject(name, conf, index, object->id);
// });
VLC->modh->identifiers.registerObject(scope, "heroClass", name, object->id);
}
void CHeroClassHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
{
auto object = loadFromJson(data, name);
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
object->id = index;
assert(heroClasses[index] == nullptr); // ensure that this id was not loaded before
@ -547,7 +540,7 @@ std::vector<JsonNode> CHeroHandler::loadLegacyData(size_t dataSize)
void CHeroHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
{
auto object = loadFromJson(data, name);
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
object->ID = HeroTypeID(heroes.size());
object->imageIndex = heroes.size() + 30; // 2 special frames + some extra portraits
@ -558,7 +551,7 @@ void CHeroHandler::loadObject(std::string scope, std::string name, const JsonNod
void CHeroHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
{
auto object = loadFromJson(data, name);
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
object->ID = HeroTypeID(index);
object->imageIndex = index;
@ -618,3 +611,17 @@ std::vector<bool> CHeroHandler::getDefaultAllowedAbilities() const
allowedAbilities.resize(GameConstants::SKILL_QUANTITY, true);
return allowedAbilities;
}
si32 CHeroHandler::decodeSkill(const std::string& identifier)
{
auto rawId = VLC->modh->identifiers.getIdentifier("core", "skill", identifier);
if(rawId)
return rawId.get();
else
return -1;
}
std::string CHeroHandler::encodeSkill(const si32 index)
{
return NSecondarySkill::names[index];
}

View File

@ -257,6 +257,12 @@ public:
*/
std::vector<bool> getDefaultAllowedAbilities() const;
///json serialization helper
static si32 decodeSkill(const std::string & identifier);
///json serialization helper
static std::string encodeSkill(const si32 index);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & classes & heroes & expPerLevel & ballistics & terrCosts;

View File

@ -187,7 +187,6 @@ void CIdentifierStorage::registerObject(std::string scope, std::string type, std
checkIdentifier(fullID);
registeredObjects.insert(std::make_pair(fullID, data));
logGlobal->traceStream() << scope << "::" << fullID;
}
std::vector<CIdentifierStorage::ObjectData> CIdentifierStorage::getPossibleIdentifiers(const ObjectCallback & request)
@ -206,10 +205,21 @@ std::vector<CIdentifierStorage::ObjectData> CIdentifierStorage::getPossibleIdent
else
{
//...unless destination mod was specified explicitly
auto myDeps = VLC->modh->getModData(request.localScope).dependencies;
if (request.remoteScope == "core" || // allow only available to all core mod
myDeps.count(request.remoteScope)) // or dependencies
//note: getModData does not work for "core" by design
//for map format support core mod has access to any mod
//TODO: better solution for access from map?
if(request.localScope == "core" || request.localScope == "")
{
allowedScopes.insert(request.remoteScope);
}
else
{
// allow only available to all core mod or dependencies
auto myDeps = VLC->modh->getModData(request.localScope).dependencies;
if (request.remoteScope == "core" || myDeps.count(request.remoteScope))
allowedScopes.insert(request.remoteScope);
}
}
std::string fullID = request.type + '.' + request.name;
@ -845,9 +855,16 @@ void CModHandler::loadModFilesystems()
CModInfo & CModHandler::getModData(TModID modId)
{
CModInfo & mod = allMods.at(modId);
assert(vstd::contains(activeMods, modId)); // not really necessary but won't hurt
return mod;
auto it = allMods.find(modId);
if(it == allMods.end())
{
throw std::runtime_error("Mod not found '" + modId+"'");
}
else
{
return it->second;
}
}
void CModHandler::initializeConfig()

View File

@ -682,7 +682,7 @@ CFaction * CTownHandler::loadFromJson(const JsonNode &source, const std::string
void CTownHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
{
auto object = loadFromJson(data, name);
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
object->index = factions.size();
factions.push_back(object);
@ -699,7 +699,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() = object->identifier;
config["faction"].String() = name;
config["faction"].meta = scope;
if (config.meta.empty())// MODS COMPATIBILITY FOR 0.96
config.meta = scope;
@ -722,7 +722,7 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod
void CTownHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
{
auto object = loadFromJson(data, name);
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
object->index = index;
assert(factions[index] == nullptr); // ensure that this id was not loaded before
factions[index] = object;
@ -739,7 +739,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() = object->identifier;
config["faction"].String() = name;
config["faction"].meta = scope;
VLC->objtypeh->loadSubObject(object->identifier, config, index, object->index);
});

View File

@ -17,3 +17,8 @@ void IHandlerBase::registerObject(std::string scope, std::string type_name, std:
{
return VLC->modh->identifiers.registerObject(scope, type_name, name, index);
}
std::string IHandlerBase::normalizeIdentifier(const std::string& scope, const std::string& remoteScope, const std::string& identifier) const
{
return VLC->modh->normalizeIdentifier(scope, remoteScope, identifier);
}

View File

@ -25,6 +25,7 @@ class DLL_LINKAGE IHandlerBase
protected:
/// Calls modhandler. Mostly needed to avoid large number of includes in headers
void registerObject(std::string scope, std::string type_name, std::string name, si32 index);
std::string normalizeIdentifier(const std::string & scope, const std::string & remoteScope, const std::string & identifier) const;
public:
/// loads all original game data in vector of json nodes
@ -65,7 +66,7 @@ public:
void loadObject(std::string scope, std::string name, const JsonNode & data) override
{
auto type_name = getTypeName();
auto object = loadFromJson(data, name);
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
object->id = _ObjectID(objects.size());
objects.push_back(object);
@ -75,7 +76,7 @@ public:
void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override
{
auto type_name = getTypeName();
auto object = loadFromJson(data, name);
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
object->id = _ObjectID(index);

View File

@ -201,14 +201,14 @@ CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(co
void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
{
auto object = loadFromJson(data, name);
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
objects[object->id] = object;
VLC->modh->identifiers.registerObject(scope, "object", name, object->id);
}
void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
{
auto object = loadFromJson(data, name);
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
assert(objects[index] == nullptr); // ensure that this id was not loaded before
objects[index] = object;
VLC->modh->identifiers.registerObject(scope, "object", name, object->id);

View File

@ -23,6 +23,7 @@
#include "../mapObjects/CObjectClassesHandler.h"
#include "../mapObjects/CGHeroInstance.h"
#include "../mapObjects/CGTownInstance.h"
#include "../spells/CSpellHandler.h"
#include "../StringConstants.h"
#include "../serializer/JsonDeserializer.h"
#include "../serializer/JsonSerializer.h"
@ -432,6 +433,35 @@ void CMapFormatJson::writeTriggeredEvent(const TriggeredEvent& event, JsonNode&
dest["condition"] = event.trigger.toJson(ConditionToJson);
}
void CMapFormatJson::serializeOptions(JsonSerializeFormat & handler)
{
//rumors
//disposedHeroes
//predefinedHeroes
handler.serializeLIC("allowedAbilities", &CHeroHandler::decodeSkill, &CHeroHandler::encodeSkill, VLC->heroh->getDefaultAllowedAbilities(), map->allowedAbilities);
handler.serializeLIC("allowedArtifacts", &CArtHandler::decodeArfifact, &CArtHandler::encodeArtifact, VLC->arth->getDefaultAllowed(), map->allowedArtifact);
handler.serializeLIC("allowedSpells", &CSpellHandler::decodeSpell, &CSpellHandler::encodeSpell, VLC->spellh->getDefaultAllowed(), map->allowedSpell);
//events
}
void CMapFormatJson::readOptions(JsonDeserializer & handler)
{
serializeOptions(handler);
}
void CMapFormatJson::writeOptions(JsonSerializer & handler)
{
serializeOptions(handler);
}
///CMapPatcher
CMapPatcher::CMapPatcher(JsonNode stream):
input(stream)
@ -490,7 +520,7 @@ std::unique_ptr<CMapHeader> CMapLoaderJson::loadMapHeader()
map = nullptr;
std::unique_ptr<CMapHeader> result = std::unique_ptr<CMapHeader>(new CMapHeader());
mapHeader = result.get();
readHeader();
readHeader(false);
return std::move(result);
}
@ -512,7 +542,7 @@ const JsonNode CMapLoaderJson::getFromArchive(const std::string & archiveFilenam
void CMapLoaderJson::readMap()
{
LOG_TRACE(logGlobal);
readHeader();
readHeader(true);
map->initTerrain();
readTerrain();
readObjects();
@ -525,7 +555,7 @@ void CMapLoaderJson::readMap()
map->calculateGuardingGreaturePositions();
}
void CMapLoaderJson::readHeader()
void CMapLoaderJson::readHeader(const bool complete)
{
//do not use map field here, use only mapHeader
JsonNode header = getFromArchive(HEADER_FILE_NAME);
@ -575,6 +605,9 @@ void CMapLoaderJson::readHeader()
readTeams(handler);
//TODO: readHeader
if(complete)
readOptions(handler);
}
@ -900,6 +933,8 @@ void CMapSaverJson::writeHeader()
//todo: allowedHeroes;
//todo: placeholdedHeroes;
writeOptions(handler);
addToArchive(header, HEADER_FILE_NAME);
}

View File

@ -56,13 +56,11 @@ protected:
/**
* Reads team settings to header
* @param input serialized header
*/
void readTeams(JsonDeserializer & handler);
/**
* Saves team settings to header
* @param output serialized header
*/
void writeTeams(JsonSerializer & handler);
@ -89,6 +87,21 @@ protected:
* Writes one of triggered events
*/
void writeTriggeredEvent(const TriggeredEvent & event, JsonNode & dest);
///common part of map attributes saving/loading
void serializeOptions(JsonSerializeFormat & handler);
/**
* Loads map attributes except header ones
*/
void readOptions(JsonDeserializer & handler);
/**
* Saves map attributes except header ones
*/
void writeOptions(JsonSerializer & handler);
};
class DLL_LINKAGE CMapPatcher : public CMapFormatJson, public IMapPatcher
@ -166,7 +179,7 @@ private:
/**
* Reads the map header.
*/
void readHeader();
void readHeader(const bool complete);
/**
* Reads complete map.

View File

@ -54,11 +54,33 @@ void JsonDeserializer::serializeLIC(const std::string & fieldName, const TDecode
if(field.isNull())
return;
auto loadPart = [&](const JsonVector & part, const bool val)
{
for(size_t index = 0; index < part.size(); index++)
{
const std::string & identifier = part[index].String();
logGlobal->debugStream() << "serializeLIC: " << fieldName << " " << identifier;
si32 rawId = decoder(identifier);
if(rawId >= 0)
{
if(rawId < value.size())
value[rawId] = val;
else
logGlobal->errorStream() << "JsonDeserializer::serializeLIC: " << fieldName <<" id out of bounds " << rawId;
}
else
{
logGlobal->errorStream() << "JsonDeserializer::serializeLIC: " << fieldName <<" identifier not resolved " << identifier;
}
}
};
const JsonVector & anyOf = field["anyOf"].Vector();
const JsonVector & allOf = field["allOf"].Vector();
const JsonVector & noneOf = field["noneOf"].Vector();
if(anyOf.empty() && allOf.empty())
{
//permissive mode
@ -70,35 +92,11 @@ void JsonDeserializer::serializeLIC(const std::string & fieldName, const TDecode
value.clear();
value.resize(standard.size(), false);
for(size_t index = 0; index < anyOf.size(); index++)
{
const std::string & identifier = anyOf[index].String();
si32 rawId = decoder(identifier);
if(rawId >= 0)
value[rawId] = true;
}
for(size_t index = 0; index < allOf.size(); index++)
{
const std::string & identifier = allOf[index].String();
si32 rawId = decoder(identifier);
if(rawId >=0)
value[rawId] = true;
}
}
for(size_t index = 0; index < noneOf.size(); index++)
{
const std::string & identifier = noneOf[index].String();
si32 rawId = decoder(identifier);
if(rawId >=0 )
value[rawId] = false;
loadPart(anyOf, true);
loadPart(allOf, true);
}
loadPart(noneOf, false);
}
void JsonDeserializer::serializeString(const std::string & fieldName, std::string & value)

View File

@ -1078,6 +1078,27 @@ CSpellHandler::~CSpellHandler()
std::vector<bool> CSpellHandler::getDefaultAllowed() const
{
std::vector<bool> allowedSpells;
allowedSpells.resize(GameConstants::SPELLS_QUANTITY, true);
allowedSpells.reserve(objects.size());
for(const CSpell * s : objects)
{
allowedSpells.push_back( !(s->isSpecialSpell() || s->isCreatureAbility()));
}
return allowedSpells;
}
si32 CSpellHandler::decodeSpell(const std::string& identifier)
{
auto rawId = VLC->modh->identifiers.getIdentifier("core", "spell", identifier);
if(rawId)
return rawId.get();
else
return -1;
}
std::string CSpellHandler::encodeSpell(const si32 index)
{
return VLC->spellh->objects[index]->identifier;
}

View File

@ -360,6 +360,12 @@ public:
const std::string getTypeName() const override;
///json serialization helper
static si32 decodeSpell(const std::string & identifier);
///json serialization helper
static std::string encodeSpell(const si32 index);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & objects ;

View File

@ -26,6 +26,16 @@ void checkEqual(const T & actual, const T & expected)
BOOST_CHECK_EQUAL(actual, expected) ;
}
void checkEqual(const std::vector<bool> & actual, const std::vector<bool> & expected)
{
BOOST_CHECK_EQUAL(actual.size(), expected.size());
for(auto actualIt = actual.begin(), expectedIt = expected.begin(); actualIt != actual.end() && expectedIt != expected.end(); actualIt++, expectedIt++)
{
checkEqual(*actualIt, *expectedIt);
}
}
template <class Element>
void checkEqual(const std::vector<Element> & actual, const std::vector<Element> & expected)
{
@ -89,6 +99,20 @@ void checkEqual(const TriggeredEvent & actual, const TriggeredEvent & expected)
checkEqual(actual.trigger, expected.trigger);
}
void checkEqual(const Rumor & actual, const Rumor & expected)
{
VCMI_CHECK_FIELD_EQUAL(name);
VCMI_CHECK_FIELD_EQUAL(text);
}
void checkEqual(const DisposedHero & actual, const DisposedHero & expected)
{
VCMI_CHECK_FIELD_EQUAL(heroId);
VCMI_CHECK_FIELD_EQUAL(portrait);
VCMI_CHECK_FIELD_EQUAL(name);
VCMI_CHECK_FIELD_EQUAL(players);
}
void checkEqual(const TerrainTile & actual, const TerrainTile & expected)
{
//fatal fail here on any error
@ -138,14 +162,16 @@ void MapComparer::compareHeader()
void MapComparer::compareOptions()
{
//rumors
//disposedHeroes
//predefinedHeroes
//allowedSpell
//allowedArtifact
//allowedAbilities
checkEqual(actual->rumors, expected->rumors);
checkEqual(actual->disposedHeroes, expected->disposedHeroes);
//todo: compareOptions predefinedHeroes
BOOST_ERROR("Not implemented compareOptions()");
checkEqual(actual->allowedAbilities, expected->allowedAbilities);
checkEqual(actual->allowedArtifact, expected->allowedArtifact);
checkEqual(actual->allowedSpell, expected->allowedSpell);
//checkEqual(actual->allowedAbilities, expected->allowedAbilities);
//todo: compareOptions events
}
void MapComparer::compareObject(const CGObjectInstance * actual, const CGObjectInstance * expected)