/* * helper.cpp, 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 * */ #include "StdInc.h" #include "helper.h" #include "mapcontroller.h" #include "../lib/filesystem/Filesystem.h" #include "../lib/filesystem/CMemoryBuffer.h" #include "../lib/filesystem/CFilesystemLoader.h" #include "../lib/filesystem/CZipSaver.h" #include "../lib/campaign/CampaignHandler.h" #include "../lib/mapping/CMapService.h" #include "../lib/mapping/CMap.h" #include "../lib/mapping/CMap.h" #include "../lib/mapping/MapFormatJson.h" #include "../lib/modding/ModIncompatibility.h" #include "../lib/rmg/CRmgTemplate.h" #include "../lib/serializer/JsonSerializer.h" #include "../lib/serializer/JsonDeserializer.h" #include "../lib/serializer/CSaveFile.h" ResourcePath addFilesystemAndGetResource(const QString & filenameSelect, EResType type, const std::string & typeName) { QFileInfo fi(filenameSelect); std::string fname = fi.fileName().toStdString(); std::string fdir = fi.dir().path().toStdString(); ResourcePath resId("MAPEDITOR/" + fname, type); //addFilesystem takes care about memory deallocation if case of failure, no memory leak here auto mapEditorFilesystem = std::make_unique("MAPEDITOR/", fdir, 0); CResourceHandler::removeFilesystem("local", "mapEditor"); CResourceHandler::addFilesystem("local", "mapEditor", std::move(mapEditorFilesystem)); if(!CResourceHandler::get("mapEditor")->existsResource(resId)) throw std::runtime_error("Cannot open " + typeName + " from this folder"); return resId; } std::unique_ptr Helper::openMapInternal(const QString & filenameSelect, IGameInfoCallback * cb) { auto resId = addFilesystemAndGetResource(filenameSelect, EResType::MAP, "map"); CMapService mapService; if(auto header = mapService.loadMapHeader(resId)) { auto missingMods = CMapService::verifyMapHeaderMods(*header); ModIncompatibility::ModList modList; for(const auto & m : missingMods) modList.push_back(m.second.name); if(!modList.empty()) throw ModIncompatibility(modList); return mapService.loadMap(resId, cb); } else throw std::runtime_error("Corrupted map"); } std::shared_ptr Helper::openCampaignInternal(const QString & filenameSelect) { auto resId = addFilesystemAndGetResource(filenameSelect, EResType::CAMPAIGN, "campaign"); if(auto campaign = CampaignHandler::getCampaign(resId.getName())) return campaign; else throw std::runtime_error("Corrupted campaign"); } std::map> Helper::openTemplateInternal(const QString & filenameSelect) { auto resId = addFilesystemAndGetResource(filenameSelect, EResType::JSON, "template"); auto data = CResourceHandler::get()->load(resId)->readAll(); JsonNode nodes(reinterpret_cast(data.first.get()), data.second, resId.getName()); std::map> templates; for(auto & node : nodes.Struct()) { JsonDeserializer handler(nullptr, node.second); auto rmg = std::make_shared(); rmg->serializeJson(handler); rmg->validate(); templates[node.first] = rmg; } return templates; } void Helper::saveCampaign(std::shared_ptr campaignState, const QString & filename) { auto jsonCampaign = CampaignHandler::writeHeaderToJson(*campaignState); auto io = std::make_shared(); auto saver = std::make_shared(io, filename.toStdString()); for(auto & scenario : campaignState->allScenarios()) { EditorCallback cb(nullptr); auto map = campaignState->getMap(scenario, &cb); cb.setMap(map.get()); MapController::repairMap(map.get()); CMemoryBuffer serializeBuffer; { CMapSaverJson jsonSaver(&serializeBuffer); jsonSaver.saveMap(map); } auto mapName = boost::algorithm::to_lower_copy(campaignState->scenario(scenario).mapName); if(!boost::ends_with(mapName, ".vmap")) mapName = boost::replace_all_copy(mapName, ".h3m", std::string("")) + ".vmap"; auto stream = saver->addFile(mapName); stream->write(reinterpret_cast(serializeBuffer.getBuffer().data()), serializeBuffer.getSize()); jsonCampaign["scenarios"].Vector().push_back(CampaignHandler::writeScenarioToJson(campaignState->scenario(scenario))); jsonCampaign["scenarios"].Vector().back()["map"].String() = mapName; } auto jsonCampaignStr = jsonCampaign.toString(); saver->addFile("header.json")->write(reinterpret_cast(jsonCampaignStr.data()), jsonCampaignStr.length()); } void Helper::saveTemplate(std::map> tpl, const QString & filename) { JsonMap data; for(auto & node : tpl) { JsonNode actual; { JsonSerializer handler(nullptr, actual); node.second->serializeJson(handler); } data[node.first] = actual; } auto byteData = JsonNode(data).toBytes(); QByteArray byteDataArray(reinterpret_cast(byteData.data()), static_cast(byteData.size())); QFile file(filename); if(file.open(QIODevice::WriteOnly)) file.write(byteDataArray); }