mirror of
https://github.com/vcmi/vcmi.git
synced 2025-02-03 13:01:33 +02:00
Merge pull request #1177 from IvanSavenko/fix_mod_identifiers
Fix mod identifiers registration & incorrect mod validation
This commit is contained in:
commit
d9c4b28ccc
@ -373,8 +373,8 @@ CArtifact * CArtHandler::loadFromJson(const std::string & scope, const JsonNode
|
||||
if(!art->advMapDef.empty())
|
||||
{
|
||||
JsonNode templ;
|
||||
templ.setMeta(scope);
|
||||
templ["animation"].String() = art->advMapDef;
|
||||
templ.setMeta(scope);
|
||||
|
||||
// add new template.
|
||||
// Necessary for objects added via mods that don't have any templates in H3
|
||||
|
@ -633,6 +633,7 @@ CCreature * CCreatureHandler::loadFromJson(const std::string & scope, const Json
|
||||
{
|
||||
JsonNode templ;
|
||||
templ["animation"].String() = cre->advMapDef;
|
||||
templ.setMeta(scope);
|
||||
VLC->objtypeh->getHandlerFor(Obj::MONSTER, cre->idNumber.num)->addTemplate(templ);
|
||||
}
|
||||
|
||||
|
@ -206,39 +206,54 @@ std::vector<CIdentifierStorage::ObjectData> CIdentifierStorage::getPossibleIdent
|
||||
std::set<std::string> allowedScopes;
|
||||
bool isValidScope = true;
|
||||
|
||||
// called have not specified destination mod explicitly
|
||||
if (request.remoteScope.empty())
|
||||
{
|
||||
// FIXME: temporary, for queries from map loader allow access to any identifer
|
||||
// should be changed to list of mods that are marked as required by current map
|
||||
if (request.localScope == "map")
|
||||
{
|
||||
for (auto const & modName : VLC->modh->getActiveMods())
|
||||
allowedScopes.insert(modName);
|
||||
}
|
||||
|
||||
// normally ID's from all required mods, own mod and virtual "core" mod are allowed
|
||||
if(request.localScope != "core" && !request.localScope.empty())
|
||||
else if(request.localScope != "core" && !request.localScope.empty())
|
||||
{
|
||||
allowedScopes = VLC->modh->getModDependencies(request.localScope, isValidScope);
|
||||
|
||||
if(!isValidScope)
|
||||
return std::vector<ObjectData>();
|
||||
|
||||
allowedScopes.insert(request.localScope);
|
||||
}
|
||||
allowedScopes.insert(request.localScope);
|
||||
|
||||
// all mods can access built-in mod
|
||||
allowedScopes.insert("core");
|
||||
}
|
||||
else
|
||||
{
|
||||
//...unless destination mod was specified explicitly
|
||||
//note: getModDependencies does not work for "core" by design
|
||||
//if destination mod was specified explicitly, restrict lookup to this mod
|
||||
|
||||
//for map format support core mod has access to any mod
|
||||
//TODO: better solution for access from map?
|
||||
if(request.localScope == "core" || request.localScope.empty())
|
||||
if(request.remoteScope == "core" )
|
||||
{
|
||||
//"core" mod is an implicit dependency for all mods, allow access into it
|
||||
allowedScopes.insert(request.remoteScope);
|
||||
}
|
||||
else if(request.remoteScope == request.localScope )
|
||||
{
|
||||
// allow self-access
|
||||
allowedScopes.insert(request.remoteScope);
|
||||
}
|
||||
else
|
||||
{
|
||||
// allow only available to all core mod or dependencies
|
||||
// allow access only if mod is in our dependencies
|
||||
auto myDeps = VLC->modh->getModDependencies(request.localScope, isValidScope);
|
||||
|
||||
if(!isValidScope)
|
||||
return std::vector<ObjectData>();
|
||||
|
||||
if(request.remoteScope == "core" || request.remoteScope == request.localScope || myDeps.count(request.remoteScope))
|
||||
if(myDeps.count(request.remoteScope))
|
||||
allowedScopes.insert(request.remoteScope);
|
||||
}
|
||||
}
|
||||
@ -296,10 +311,14 @@ void CIdentifierStorage::finalize()
|
||||
state = FINALIZING;
|
||||
bool errorsFound = false;
|
||||
|
||||
//Note: we may receive new requests during resolution phase -> end may change -> range for can't be used
|
||||
for(auto it = scheduledRequests.begin(); it != scheduledRequests.end(); it++)
|
||||
while ( !scheduledRequests.empty() )
|
||||
{
|
||||
errorsFound |= !resolveIdentifier(*it);
|
||||
// Use local copy since new requests may appear during resolving, invalidating any iterators
|
||||
auto request = scheduledRequests.back();
|
||||
scheduledRequests.pop_back();
|
||||
|
||||
if (!resolveIdentifier(request))
|
||||
errorsFound = true;
|
||||
}
|
||||
|
||||
if (errorsFound)
|
||||
|
@ -1014,7 +1014,7 @@ const JsonNode & JsonUtils::getSchema(std::string URI)
|
||||
return getSchemaByName(filename).resolvePointer(URI.substr(posHash + 1));
|
||||
}
|
||||
|
||||
void JsonUtils::merge(JsonNode & dest, JsonNode & source, bool noOverride)
|
||||
void JsonUtils::merge(JsonNode & dest, JsonNode & source, bool ignoreOverride, bool copyMeta)
|
||||
{
|
||||
if (dest.getType() == JsonNode::JsonType::DATA_NULL)
|
||||
{
|
||||
@ -1022,6 +1022,14 @@ void JsonUtils::merge(JsonNode & dest, JsonNode & source, bool noOverride)
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasNull = dest.isNull() || source.isNull();
|
||||
bool sameType = dest.getType() == source.getType();
|
||||
bool sourceNumeric = source.getType() == JsonNode::JsonType::DATA_FLOAT || source.getType() == JsonNode::JsonType::DATA_INTEGER;
|
||||
bool destNumeric = dest.getType() == JsonNode::JsonType::DATA_FLOAT || dest.getType() == JsonNode::JsonType::DATA_INTEGER;
|
||||
bool bothNumeric = sourceNumeric && destNumeric;
|
||||
|
||||
assert( hasNull || sameType || bothNumeric );
|
||||
|
||||
switch (source.getType())
|
||||
{
|
||||
case JsonNode::JsonType::DATA_NULL:
|
||||
@ -1040,30 +1048,33 @@ void JsonUtils::merge(JsonNode & dest, JsonNode & source, bool noOverride)
|
||||
}
|
||||
case JsonNode::JsonType::DATA_STRUCT:
|
||||
{
|
||||
if(!noOverride && vstd::contains(source.flags, "override"))
|
||||
if(!ignoreOverride && vstd::contains(source.flags, "override"))
|
||||
{
|
||||
std::swap(dest, source);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (copyMeta)
|
||||
dest.meta = source.meta;
|
||||
|
||||
//recursively merge all entries from struct
|
||||
for(auto & node : source.Struct())
|
||||
merge(dest[node.first], node.second, noOverride);
|
||||
merge(dest[node.first], node.second, ignoreOverride);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JsonUtils::mergeCopy(JsonNode & dest, JsonNode source, bool noOverride)
|
||||
void JsonUtils::mergeCopy(JsonNode & dest, JsonNode source, bool ignoreOverride, bool copyMeta)
|
||||
{
|
||||
// uses copy created in stack to safely merge two nodes
|
||||
merge(dest, source, noOverride);
|
||||
merge(dest, source, ignoreOverride, copyMeta);
|
||||
}
|
||||
|
||||
void JsonUtils::inherit(JsonNode & descendant, const JsonNode & base)
|
||||
{
|
||||
JsonNode inheritedNode(base);
|
||||
merge(inheritedNode, descendant, true);
|
||||
merge(inheritedNode, descendant, true, true);
|
||||
descendant.swap(inheritedNode);
|
||||
}
|
||||
|
||||
|
@ -184,7 +184,7 @@ namespace JsonUtils
|
||||
* null : if value in source is present but set to null it will delete entry in dest
|
||||
* @note this function will destroy data in source
|
||||
*/
|
||||
DLL_LINKAGE void merge(JsonNode & dest, JsonNode & source, bool noOverride = false);
|
||||
DLL_LINKAGE void merge(JsonNode & dest, JsonNode & source, bool ignoreOverride = false, bool copyMeta = false);
|
||||
|
||||
/**
|
||||
* @brief recursively merges source into dest, replacing identical fields
|
||||
@ -194,7 +194,7 @@ namespace JsonUtils
|
||||
* null : if value in source is present but set to null it will delete entry in dest
|
||||
* @note this function will preserve data stored in source by creating copy
|
||||
*/
|
||||
DLL_LINKAGE void mergeCopy(JsonNode & dest, JsonNode source, bool noOverride = false);
|
||||
DLL_LINKAGE void mergeCopy(JsonNode & dest, JsonNode source, bool ignoreOverride = false, bool copyMeta = false);
|
||||
|
||||
/** @brief recursively merges descendant into copy of base node
|
||||
* Result emulates inheritance semantic
|
||||
|
@ -26,14 +26,6 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
// FIXME: move into inheritNode?
|
||||
static void inheritNodeWithMeta(JsonNode & descendant, const JsonNode & base)
|
||||
{
|
||||
std::string oldMeta = descendant.meta;
|
||||
JsonUtils::inherit(descendant, base);
|
||||
descendant.setMeta(oldMeta);
|
||||
}
|
||||
|
||||
CObjectClassesHandler::CObjectClassesHandler()
|
||||
{
|
||||
#define SET_HANDLER_CLASS(STRING, CLASSNAME) handlerConstructors[STRING] = std::make_shared<CLASSNAME>;
|
||||
@ -291,8 +283,9 @@ void CObjectClassesHandler::loadSubObject(const std::string & identifier, JsonNo
|
||||
assert(objects.at(ID)->subObjects.count(subID.get()) == 0);
|
||||
assert(config["index"].isNull());
|
||||
config["index"].Float() = subID.get();
|
||||
config["index"].setMeta(config.meta);
|
||||
}
|
||||
inheritNodeWithMeta(config, objects.at(ID)->base);
|
||||
JsonUtils::inherit(config, objects.at(ID)->base);
|
||||
loadObjectEntry(identifier, config, objects[ID], isSubObject);
|
||||
}
|
||||
|
||||
@ -319,9 +312,9 @@ TObjectTypeHandler CObjectClassesHandler::getHandlerFor(si32 type, si32 subtype)
|
||||
throw std::runtime_error("Object type handler not found");
|
||||
}
|
||||
|
||||
TObjectTypeHandler CObjectClassesHandler::getHandlerFor(std::string type, std::string subtype) const
|
||||
TObjectTypeHandler CObjectClassesHandler::getHandlerFor(std::string scope, std::string type, std::string subtype) const
|
||||
{
|
||||
boost::optional<si32> id = VLC->modh->identifiers.getIdentifier("core", "object", type, false);
|
||||
boost::optional<si32> id = VLC->modh->identifiers.getIdentifier(scope, "object", type, false);
|
||||
if(id)
|
||||
{
|
||||
auto object = objects.at(id.get());
|
||||
@ -367,11 +360,9 @@ void CObjectClassesHandler::beforeValidate(JsonNode & object)
|
||||
{
|
||||
for (auto & entry : object["types"].Struct())
|
||||
{
|
||||
inheritNodeWithMeta(entry.second, object["base"]);
|
||||
JsonUtils::inherit(entry.second, object["base"]);
|
||||
for (auto & templ : entry.second["templates"].Struct())
|
||||
{
|
||||
inheritNodeWithMeta(templ.second, entry.second["base"]);
|
||||
}
|
||||
JsonUtils::inherit(templ.second, entry.second["base"]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,7 +303,7 @@ public:
|
||||
|
||||
/// returns handler for specified object (ID-based). ObjectHandler keeps ownership
|
||||
TObjectTypeHandler getHandlerFor(si32 type, si32 subtype) const;
|
||||
TObjectTypeHandler getHandlerFor(std::string type, std::string subtype) const;
|
||||
TObjectTypeHandler getHandlerFor(std::string scope, std::string type, std::string subtype) const;
|
||||
TObjectTypeHandler getHandlerFor(CompoundMapObjectID compoundIdentifier) const;
|
||||
|
||||
std::string getObjectName(si32 type) const;
|
||||
|
@ -44,6 +44,10 @@ void CTownInstanceConstructor::initTypeData(const JsonNode & input)
|
||||
});
|
||||
|
||||
filtersJson = input["filters"];
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
void CTownInstanceConstructor::afterLoadFinalization()
|
||||
|
@ -1121,7 +1121,7 @@ void CMapLoaderJson::MapObjectLoader::construct()
|
||||
return;
|
||||
}
|
||||
|
||||
auto handler = VLC->objtypeh->getHandlerFor(typeName, subtypeName);
|
||||
auto handler = VLC->objtypeh->getHandlerFor( "map", typeName, subtypeName);
|
||||
|
||||
auto appearance = new ObjectTemplate;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user