1
0
mirror of https://github.com/vcmi/vcmi.git synced 2026-04-26 20:02:20 +02:00
Files

192 lines
6.2 KiB
C++
Raw Permalink Normal View History

/*
* CMapService.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
*
*/
2012-11-21 09:13:33 +00:00
#include "StdInc.h"
#include "CMapService.h"
2025-06-02 15:19:08 +03:00
#include "MapFormatSettings.h"
#include "../json/JsonUtils.h"
2013-07-28 14:49:50 +00:00
#include "../filesystem/Filesystem.h"
2013-04-07 10:48:07 +00:00
#include "../filesystem/CBinaryReader.h"
#include "../filesystem/CCompressedStream.h"
#include "../filesystem/CMemoryStream.h"
#include "../filesystem/CMemoryBuffer.h"
#include "../modding/CModHandler.h"
2024-11-09 20:29:07 +00:00
#include "../modding/ModDescription.h"
#include "../modding/ModScope.h"
#include "../GameLibrary.h"
2016-02-13 19:43:05 +03:00
#include "CMap.h"
2023-05-24 01:14:06 +03:00
#include "MapFormat.h"
2013-02-02 17:20:31 +00:00
#include "MapFormatH3M.h"
#include "MapFormatJson.h"
2026-02-07 21:00:14 +01:00
#include "../callback/EditorCallback.h"
VCMI_LIB_NAMESPACE_BEGIN
std::unique_ptr<CMap> CMapService::loadMap(const ResourcePath & name, IGameInfoCallback * cb) const
{
std::string modName = LIBRARY->modh->findResourceOrigin(name);
std::string encoding = LIBRARY->modh->findResourceEncoding(name);
auto stream = getStreamFromFS(name);
2026-02-07 21:00:14 +01:00
auto loader = getMapLoader(stream, name.getName(), modName, encoding);
// If JSON loader, let it know whether this is editor callback
if(auto jsonLoader = dynamic_cast<CMapLoaderJson*>(loader.get()))
jsonLoader->setRunningInMapEditor(dynamic_cast<EditorCallback*>(cb) != nullptr);
return loader->loadMap(cb);
}
2026-02-07 21:00:14 +01:00
std::unique_ptr<CMapHeader> CMapService::loadMapHeader(const ResourcePath & name, bool isEditor) const
{
std::string modName = LIBRARY->modh->findResourceOrigin(name);
std::string encoding = LIBRARY->modh->findResourceEncoding(name);
auto stream = getStreamFromFS(name);
2026-02-07 21:00:14 +01:00
auto loader = getMapLoader(stream, name.getName(), modName, encoding);
// default: not editor; callers may pass explicit overload if needed
if(auto jsonLoader = dynamic_cast<CMapLoaderJson*>(loader.get()))
jsonLoader->setRunningInMapEditor(false);
return loader->loadMapHeader();
}
std::unique_ptr<CMap> CMapService::loadMap(const uint8_t * buffer, int size, const std::string & name, const std::string & modName, const std::string & encoding, IGameInfoCallback * cb) const
{
auto stream = getStreamFromMem(buffer, size);
2026-02-07 21:00:14 +01:00
auto loader = getMapLoader(stream, name, modName, encoding);
if(auto jsonLoader = dynamic_cast<CMapLoaderJson*>(loader.get()))
jsonLoader->setRunningInMapEditor(dynamic_cast<EditorCallback*>(cb) != nullptr);
std::unique_ptr<CMap> map(loader->loadMap(cb));
std::unique_ptr<CMapHeader> header(map.get());
2017-06-04 22:42:48 +03:00
//might be original campaign and require patch
getMapPatcher(name)->patchMapHeader(header);
header.release();
2015-12-04 01:06:02 +02:00
return map;
}
std::unique_ptr<CMapHeader> CMapService::loadMapHeader(const uint8_t * buffer, int size, const std::string & name, const std::string & modName, const std::string & encoding) const
{
auto stream = getStreamFromMem(buffer, size);
2026-02-07 21:00:14 +01:00
auto loader = getMapLoader(stream, name, modName, encoding);
if(auto jsonLoader = dynamic_cast<CMapLoaderJson*>(loader.get()))
jsonLoader->setRunningInMapEditor(false);
std::unique_ptr<CMapHeader> header = loader->loadMapHeader();
2017-06-04 22:42:48 +03:00
//might be original campaign and require patch
getMapPatcher(name)->patchMapHeader(header);
2015-12-04 01:06:02 +02:00
return header;
}
void CMapService::saveMap(const std::unique_ptr<CMap> & map, boost::filesystem::path fullPath) const
{
CMemoryBuffer serializeBuffer;
{
CMapSaverJson saver(&serializeBuffer);
saver.saveMap(map);
}
{
boost::filesystem::remove(fullPath);
2023-07-28 15:51:14 +03:00
std::ofstream tmp(fullPath.c_str(), std::ofstream::binary);
2023-02-11 19:30:06 +03:00
tmp.write(reinterpret_cast<const char *>(serializeBuffer.getBuffer().data()), serializeBuffer.getSize());
tmp.flush();
tmp.close();
}
}
2023-04-16 15:38:13 +04:00
ModCompatibilityInfo CMapService::verifyMapHeaderMods(const CMapHeader & map)
{
const auto & activeMods = LIBRARY->modh->getActiveMods();
2023-09-21 04:31:08 +02:00
ModCompatibilityInfo missingMods;
ModCompatibilityInfo missingModsFiltered;
2023-04-16 15:38:13 +04:00
for(const auto & mapMod : map.mods)
{
if(vstd::contains(activeMods, mapMod.first))
{
const auto & modInfo = LIBRARY->modh->getModInfo(mapMod.first);
2024-11-09 20:29:07 +00:00
if(modInfo.getVersion().compatible(mapMod.second.version))
2023-04-16 15:38:13 +04:00
continue;
}
2023-09-21 22:38:01 +02:00
missingMods[mapMod.first] = mapMod.second;
}
//filter child mods
for(const auto & mapMod : missingMods)
{
if(!mapMod.second.parent.empty() && missingMods.count(mapMod.second.parent))
continue;
missingModsFiltered.insert(mapMod);
}
return missingModsFiltered;
2023-04-16 15:38:13 +04:00
}
std::unique_ptr<CInputStream> CMapService::getStreamFromFS(const ResourcePath & name)
{
2017-06-04 22:42:48 +03:00
return CResourceHandler::get()->load(name);
}
std::unique_ptr<CInputStream> CMapService::getStreamFromMem(const uint8_t * buffer, int size)
{
return std::unique_ptr<CInputStream>(new CMemoryStream(buffer, size));
}
2023-02-25 17:44:15 +02:00
std::unique_ptr<IMapLoader> CMapService::getMapLoader(std::unique_ptr<CInputStream> & stream, std::string mapName, std::string modName, std::string encoding)
{
// Read map header
CBinaryReader reader(stream.get());
ui32 header = reader.readUInt32();
reader.getStream()->seek(0);
2016-02-09 20:20:03 +03:00
//check for ZIP magic. Zip files are VCMI maps
switch(header)
{
2016-02-09 20:20:03 +03:00
case 0x06054b50:
case 0x04034b50:
case 0x02014b50:
2026-01-09 01:35:25 +01:00
return std::unique_ptr<IMapLoader>(new CMapLoaderJson(stream.get(), mapName));
2016-02-09 20:20:03 +03:00
break;
default:
// Check which map format is used
// gzip header is 3 bytes only in size
switch(header & 0xffffff)
{
// gzip header magic number, reversed for LE
case 0x00088B1F:
stream = std::unique_ptr<CInputStream>(new CCompressedStream(std::move(stream), true));
2023-02-25 17:44:15 +02:00
return std::unique_ptr<IMapLoader>(new CMapLoaderH3M(mapName, modName, encoding, stream.get()));
case static_cast<int>(EMapFormat::WOG) :
case static_cast<int>(EMapFormat::AB) :
case static_cast<int>(EMapFormat::ROE) :
case static_cast<int>(EMapFormat::SOD) :
2024-08-31 12:39:23 +02:00
case static_cast<int>(EMapFormat::CHR) :
case static_cast<int>(EMapFormat::HOTA) :
2023-02-25 17:44:15 +02:00
return std::unique_ptr<IMapLoader>(new CMapLoaderH3M(mapName, modName, encoding, stream.get()));
2016-02-09 20:20:03 +03:00
default :
throw std::runtime_error("Unknown map format");
}
}
}
std::unique_ptr<IMapPatcher> CMapService::getMapPatcher(std::string scenarioName)
{
boost::to_lower(scenarioName);
2017-08-11 20:03:05 +03:00
logGlobal->debug("Request to patch map %s", scenarioName);
2025-06-15 15:11:09 +03:00
return std::make_unique<CMapPatcher>(LIBRARY->mapFormat->mapOverrides(scenarioName));
}
VCMI_LIB_NAMESPACE_END