1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-23 00:28:08 +02:00

- it is possible to edit data of another mod or H3 data via mods

- mods can access only ID's from dependenies, virtual "core" mod and itself (optional for some mods compatibility)
- metadata field for JsonNode, used to track source mod
- moved wog creatures into wog mod
- (linux) convertMP3 option for vcmibuilder for systems where SDL_Mixer can't play mp3's
This commit is contained in:
Ivan Savenko
2013-04-25 14:03:35 +00:00
parent be6aff5173
commit 8273f323b1
24 changed files with 321 additions and 98 deletions

View File

@ -44,82 +44,142 @@ void CIdentifierStorage::checkIdentifier(std::string & ID)
}
}
void CIdentifierStorage::requestIdentifier(std::string name, const boost::function<void(si32)> & callback)
CIdentifierStorage::ObjectCallback::ObjectCallback(std::string localScope, std::string remoteScope, std::string type,
std::string name, const boost::function<void(si32)> & callback):
localScope(localScope),
remoteScope(remoteScope),
type(type),
name(name),
callback(callback)
{}
static std::pair<std::string, std::string> splitString(std::string input, char separator)
{
checkIdentifier(name);
std::pair<std::string, std::string> ret;
size_t splitPos = input.find(separator);
// old version with immediate callback posibility. Can't be used for some cases
/* auto iter = registeredObjects.find(name);
if (iter != registeredObjects.end())
callback(iter->second); //already registered - trigger callback immediately
if (splitPos == std::string::npos)
{
ret.first.clear();
ret.second = input;
}
else
{
if(boost::algorithm::starts_with(name, "primSkill."))
logGlobal->warnStream() << "incorrect primSkill name requested";
ret.first = input.substr(0, splitPos);
ret.second = input.substr(splitPos + 1);
}
return ret;
}
missingObjects[name].push_back(callback); // queue callback
}*/
void CIdentifierStorage::requestIdentifier(ObjectCallback callback)
{
checkIdentifier(callback.type);
checkIdentifier(callback.name);
missingObjects[name].push_back(callback); // queue callback
assert(!callback.localScope.empty());
scheduledRequests.push_back(callback);
}
void CIdentifierStorage::requestIdentifier(std::string scope, std::string type, std::string name, const boost::function<void(si32)> & callback)
{
auto pair = splitString(name, ':'); // remoteScope:name
requestIdentifier(ObjectCallback(scope, pair.first, type, pair.second, callback));
}
void CIdentifierStorage::requestIdentifier(std::string type, const JsonNode & name, const boost::function<void(si32)> & callback)
{
auto pair = splitString(name.String(), ':'); // remoteScope:name
requestIdentifier(ObjectCallback(name.meta, pair.first, type, pair.second, callback));
}
void CIdentifierStorage::requestIdentifier(const JsonNode & name, const boost::function<void(si32)> & callback)
{
auto pair = splitString(name.String(), ':'); // remoteScope:<type.name>
auto pair2 = splitString(pair.second, '.'); // type.name
requestIdentifier(ObjectCallback(name.meta, pair.first, pair2.first, pair2.second, callback));
}
void CIdentifierStorage::registerObject(std::string scope, std::string type, std::string name, si32 identifier)
{
//TODO: use scope
ObjectData data;
data.scope = scope;
data.id = identifier;
std::string fullID = type + '.' + name;
checkIdentifier(fullID);
// do not allow to register same object twice
assert(registeredObjects.find(fullID) == registeredObjects.end());
registeredObjects.insert(std::make_pair(fullID, data));
}
registeredObjects[fullID] = identifier;
bool CIdentifierStorage::resolveIdentifier(const ObjectCallback & request)
{
std::set<std::string> allowedScopes;
// old version with immediate callback posibility. Can't be used for some cases
/*auto iter = missingObjects.find(fullID);
if (iter != missingObjects.end())
if (request.remoteScope.empty())
{
//call all awaiting callbacks
BOOST_FOREACH(auto function, iter->second)
// normally ID's from all required mods, own mod and virtual "core" mod are allowed
if (request.localScope != "core")
allowedScopes = VLC->modh->getModData(request.localScope).dependencies;
allowedScopes.insert(request.localScope);
allowedScopes.insert("core");
}
else
{
// //...unless destination mod was specified explicitly
allowedScopes.insert(request.remoteScope);
}
std::string fullID = request.type + '.' + request.name;
auto entries = registeredObjects.equal_range(fullID);
if (entries.first != entries.second)
{
for (auto it = entries.first; it != entries.second; it++)
{
function(identifier);
if (vstd::contains(allowedScopes, it->second.scope))
{
request.callback(it->second.id);
return true;
}
}
missingObjects.erase(iter);
}*/
// error found. Try to generate some debug info
logGlobal->errorStream() << "Unknown identifier " << request.type << "." << request.name << " from mod " << request.localScope;
for (auto it = entries.first; it != entries.second; it++)
{
logGlobal->errorStream() << "\tID is available in mod " << it->second.scope;
}
// temporary code to smooth 0.92->0.93 transition
request.callback(entries.first->second.id);
return true;
}
return false;
}
void CIdentifierStorage::finalize()
{
for (auto it = missingObjects.begin(); it!= missingObjects.end();)
bool errorsFound = false;
BOOST_FOREACH(const ObjectCallback & request, scheduledRequests)
{
auto object = registeredObjects.find(it->first);
if (object != registeredObjects.end())
{
BOOST_FOREACH(auto function, it->second)
{
function(object->second);
}
it = missingObjects.erase(it);
}
else
it++;
errorsFound |= !resolveIdentifier(request);
}
// print list of missing objects and crash
// in future should try to do some cleanup (like returning all id's as 0)
if (!missingObjects.empty())
if (errorsFound)
{
BOOST_FOREACH(auto object, missingObjects)
{
logGlobal->errorStream() << "Error: object " << object.first << " was not found!";
}
BOOST_FOREACH(auto object, registeredObjects)
{
logGlobal->traceStream() << object.first << " -> " << object.second;
logGlobal->traceStream() << object.first << " -> " << object.second.id;
}
logGlobal->errorStream() << "All known identifiers were dumped into log file";
logGlobal->errorStream() << "All known identifiers were dumped into log file";
}
assert(missingObjects.empty());
assert(errorsFound == false);
}
CContentHandler::ContentTypeHandler::ContentTypeHandler(IHandlerBase * handler, size_t size, std::string objectName):
@ -127,11 +187,16 @@ CContentHandler::ContentTypeHandler::ContentTypeHandler(IHandlerBase * handler,
objectName(objectName),
originalData(handler->loadLegacyData(size))
{
BOOST_FOREACH(auto & node, originalData)
{
node.setMeta("core");
}
}
void CContentHandler::ContentTypeHandler::preloadModData(std::string modName, std::vector<std::string> fileList)
{
JsonNode data = JsonUtils::assembleFromFiles(fileList);
data.setMeta(modName);
ModInfo & modInfo = modData[modName];
@ -425,6 +490,13 @@ std::vector<std::string> CModHandler::getActiveMods()
return activeMods;
}
CModInfo & CModHandler::getModData(TModID modId)
{
CModInfo & mod = allMods.at(modId);
assert(vstd::contains(activeMods, modId)); // not really necessary but won't hurt
return mod;
}
template<typename Handler>
void CModHandler::handleData(Handler handler, const JsonNode & source, std::string listName, std::string schemaName)
{
@ -447,7 +519,7 @@ void CModHandler::loadGameContent()
CContentHandler content;
logGlobal->infoStream() << "\tInitializing content hander: " << timer.getDiff() << " ms";
// first - load virtual "core" mod tht contains all data
// first - load virtual "core" mod that contains all data
// TODO? move all data into real mods? RoE, AB, SoD, WoG
content.preloadModData("core", JsonNode(ResourceID("config/gameConfig.json")));
logGlobal->infoStream() << "\tParsing original game data: " << timer.getDiff() << " ms";
@ -475,12 +547,11 @@ void CModHandler::loadGameContent()
}
logGlobal->infoStream() << "\tLoading mod data: " << timer.getDiff() << "ms";
logGlobal->infoStream() << "\tDone loading data";
VLC->creh->loadCrExpBon();
VLC->creh->buildBonusTreeForTiers(); //do that after all new creatures are loaded
identifiers.finalize();
logGlobal->infoStream() << "\tResolving identifiers: " << timer.getDiff() << " ms";
logGlobal->infoStream() << "\tAll game content loaded in " << totalTime.getDiff() << " ms";
}