1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-23 22:37:55 +02:00
Files
vcmi/lib/modding/IdentifierStorage.h
Ivan Savenko f58d08e563 Support for banned game entities in random map templates
The following entities can now be banned in a random map template
definition:
- Hero
- Artifact
- Spell
- Secondary skill

The ban follows the same rules as banning via the map settings in the
map editor.

It is also now possible to bypass dependencies and access identifiers
from mods that are not dependencies when defining:
- Banned entities in random map templates
- the chance of a hero class appearing in a tavern of a specific faction
- the chance of a spell appearing in a mage guild of a specific faction
- the chance of a hero class receiving a secondary skill

For this to work, the identifier must be specified in full, e.g.
`modName:objectName`. If the specified mod is not active, the game will
silently ignore this entry.

This behaviour is not affected by mod load order. It is possible to use
this format to access a mod that has not yet been loaded.
2025-07-14 00:18:11 +03:00

116 lines
5.1 KiB
C++

/*
* IdentifierStorage.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 JsonNode;
/// class that stores all object identifiers strings and maps them to numeric ID's
/// if possible, objects ID's should be in format <type>.<name>, camelCase e.g. "creature.grandElf"
class DLL_LINKAGE CIdentifierStorage
{
enum class ELoadingState
{
LOADING,
FINALIZING,
FINISHED
};
struct ObjectCallback // entry created on ID request
{
std::string localScope; /// scope from which this ID was requested
std::string remoteScope; /// scope in which this object must be found
std::string type; /// type, e.g. creature, faction, hero, etc
std::string name; /// string ID
std::function<void(si32)> callback;
bool optional;
bool bypassDependenciesCheck;
bool dynamicType;
/// Builds callback from identifier in form "targetMod:type.name"
static ObjectCallback fromNameWithType(const std::string & scope, const std::string & fullName, const std::function<void(si32)> & callback, bool optional);
/// Builds callback from identifier in form "targetMod:name"
static ObjectCallback fromNameAndType(const std::string & scope, const std::string & type, const std::string & fullName, const std::function<void(si32)> & callback, bool optional, bool bypassDependenciesCheck);
private:
ObjectCallback() = default;
};
struct ObjectData // entry created on ID registration
{
si32 id;
std::string scope; /// scope in which this ID located
bool operator==(const ObjectData & other) const
{
return id == other.id && scope == other.scope;
}
};
std::multimap<std::string, ObjectData> registeredObjects;
mutable std::vector<ObjectCallback> scheduledRequests;
/// All non-optional requests that have failed to resolve, for debug & error reporting
mutable std::vector<ObjectCallback> failedRequests;
ELoadingState state = ELoadingState::LOADING;
/// Helper method that dumps all registered identifier into log file
void debugDumpIdentifiers();
/// Check if identifier can be valid (camelCase, point as separator)
static void checkIdentifier(const std::string & ID);
void requestIdentifier(const ObjectCallback & callback) const;
bool resolveIdentifier(const ObjectCallback & callback) const;
std::vector<ObjectData> getPossibleIdentifiers(const ObjectCallback & callback) const;
void showIdentifierResolutionErrorDetails(const ObjectCallback & callback) const;
std::optional<si32> getIdentifierImpl(const ObjectCallback & callback, bool silent) const;
public:
CIdentifierStorage();
virtual ~CIdentifierStorage() = default;
/// request identifier for specific object name.
/// Function callback will be called during ID resolution phase of loading
void requestIdentifier(const std::string & scope, const std::string & type, const std::string & name, const std::function<void(si32)> & callback) const;
///fullName = [remoteScope:]type.name
void requestIdentifier(const std::string & scope, const std::string & fullName, const std::function<void(si32)> & callback) const;
void requestIdentifier(const std::string & type, const JsonNode & name, const std::function<void(si32)> & callback) const;
void requestIdentifier(const JsonNode & name, const std::function<void(si32)> & callback) const;
void requestIdentifierIfNotNull(const std::string & type, const JsonNode & name, const std::function<void(si32)> & callback) const;
void requestIdentifierIfFound(const std::string & type, const JsonNode & name, const std::function<void(si32)> & callback) const;
void requestIdentifierIfFound(const std::string & scope, const std::string & type, const std::string & name, const std::function<void(si32)> & callback) const;
/// try to request ID. If ID with such name won't be loaded, callback function will not be called
void tryRequestIdentifier(const std::string & scope, const std::string & type, const std::string & name, const std::function<void(si32)> & callback) const;
void tryRequestIdentifier(const std::string & type, const JsonNode & name, const std::function<void(si32)> & callback) const;
/// get identifier immediately. If identifier is not know and not silent call will result in error message
std::optional<si32> getIdentifier(const std::string & scope, const std::string & type, const std::string & name, bool silent = false) const;
std::optional<si32> getIdentifier(const std::string & type, const JsonNode & name, bool silent = false) const;
std::optional<si32> getIdentifier(const JsonNode & name, bool silent = false) const;
std::optional<si32> getIdentifier(const std::string & scope, const std::string & fullName, bool silent = false) const;
/// registers new object
void registerObject(const std::string & scope, const std::string & type, const std::string & name, si32 identifier);
/// called at the very end of loading to check for any missing ID's
void finalize();
/// Returns list of all mods, from which at least one identifier has failed to resolve
std::vector<std::string> getModsWithFailedRequests() const;
};
VCMI_LIB_NAMESPACE_END