diff --git a/client/Client.cpp b/client/Client.cpp index 7b1e674a7..f00c05eb1 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -408,10 +408,9 @@ void CClient::newGame( CConnection *con, StartInfo *si ) // Initialize game state gs = new CGameState(); - logNetwork->infoStream() <<"\tCreating gamestate: "<info("\tCreating gamestate: %i",tmh.getDiff()); - gs->scenarioOps = si; - gs->init(si); + gs->init(si, settings["general"]["saveRandomMaps"].Bool()); logNetwork->infoStream() <<"Initializing GameState (together): "<infoStream() << "\tUsing random seed: "<< si->seedToBeUsed; getRandomGenerator().setSeed(si->seedToBeUsed); @@ -709,7 +711,7 @@ void CGameState::init(StartInfo * si) switch(scenarioOps->mode) { case StartInfo::NEW_GAME: - initNewGame(); + initNewGame(allowSavingRandomMap); break; case StartInfo::CAMPAIGN: initCampaign(); @@ -771,7 +773,7 @@ void CGameState::init(StartInfo * si) } } -void CGameState::initNewGame() +void CGameState::initNewGame(bool allowSavingRandomMap) { if(scenarioOps->createRandomMap()) { @@ -780,8 +782,37 @@ void CGameState::initNewGame() // Gen map CMapGenerator mapGenerator; - map = mapGenerator.generate(scenarioOps->mapGenOptions.get(), scenarioOps->seedToBeUsed).release(); + std::unique_ptr randomMap = mapGenerator.generate(scenarioOps->mapGenOptions.get(), scenarioOps->seedToBeUsed); + + if(allowSavingRandomMap) + { + try + { + auto path = VCMIDirs::get().userCachePath() / "RandomMaps"; + boost::filesystem::create_directories(path); + + std::shared_ptr options = scenarioOps->mapGenOptions; + + const std::string templateName = options->getMapTemplate()->getName(); + const ui32 seed = scenarioOps->seedToBeUsed; + + const std::string fileName = boost::str(boost::format("%s_%d.vmap") % templateName % seed ); + const auto fullPath = path / fileName; + + CMapService::saveMap(randomMap, fullPath); + + logGlobal->info("Random map has been saved to:"); + logGlobal->info(fullPath.string()); + } + catch(...) + { + logGlobal->error("Saving random map failed with exception"); + handleException(); + } + } + + map = randomMap.release(); // Update starting options for(int i = 0; i < map->players.size(); ++i) { diff --git a/lib/CGameState.h b/lib/CGameState.h index 69de689f8..61eafd9f5 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -201,7 +201,7 @@ public: CGameState(); virtual ~CGameState(); - void init(StartInfo * si); + void init(StartInfo * si, bool allowSavingRandomMap = false); ConstTransitivePtr scenarioOps, initialOpts; //second one is a copy of settings received from pregame (not randomized) PlayerColor currentPlayer; //ID of player currently having turn @@ -283,7 +283,7 @@ private: // ----- initialization ----- - void initNewGame(); + void initNewGame(bool allowSavingRandomMap); void initCampaign(); void initDuel(); void checkMapChecksum(); diff --git a/lib/mapping/CMapService.cpp b/lib/mapping/CMapService.cpp index 4b58c7ae6..144b1ed4c 100644 --- a/lib/mapping/CMapService.cpp +++ b/lib/mapping/CMapService.cpp @@ -5,6 +5,7 @@ #include "../filesystem/CBinaryReader.h" #include "../filesystem/CCompressedStream.h" #include "../filesystem/CMemoryStream.h" +#include "../filesystem/CMemoryBuffer.h" #include "CMap.h" @@ -52,6 +53,23 @@ std::unique_ptr CMapService::loadMapHeader(const ui8 * buffer, int s return header; } +void CMapService::saveMap(const std::unique_ptr & map, boost::filesystem::path fullPath) +{ + CMemoryBuffer serializeBuffer; + { + CMapSaverJson saver(&serializeBuffer); + saver.saveMap(map); + } + { + boost::filesystem::remove(fullPath); + boost::filesystem::ofstream tmp(fullPath, boost::filesystem::ofstream::binary); + + tmp.write((const char *)serializeBuffer.getBuffer().data(),serializeBuffer.getSize()); + tmp.flush(); + tmp.close(); + } +} + std::unique_ptr CMapService::getStreamFromFS(const std::string & name) { return CResourceHandler::get()->load(ResourceID(name, EResType::MAP)); diff --git a/lib/mapping/CMapService.h b/lib/mapping/CMapService.h index 67289ec8f..3979e9046 100644 --- a/lib/mapping/CMapService.h +++ b/lib/mapping/CMapService.h @@ -69,6 +69,7 @@ public: */ static std::unique_ptr loadMapHeader(const ui8 * buffer, int size, const std::string & name); + static void saveMap(const std::unique_ptr & map, boost::filesystem::path fullPath); private: /** * Gets a map input stream object specified by a map name. diff --git a/lib/mapping/MapFormatJson.cpp b/lib/mapping/MapFormatJson.cpp index ad8626524..dc2ac7d93 100644 --- a/lib/mapping/MapFormatJson.cpp +++ b/lib/mapping/MapFormatJson.cpp @@ -1212,6 +1212,8 @@ void CMapSaverJson::saveMap(const std::unique_ptr& map) void CMapSaverJson::writeHeader() { + logGlobal->trace("Saving header"); + JsonNode header; JsonSerializer handler(mapObjectResolver.get(), header); @@ -1283,6 +1285,7 @@ JsonNode CMapSaverJson::writeTerrainLevel(const int index) void CMapSaverJson::writeTerrain() { + logGlobal->trace("Saving terrain"); //todo: multilevel map save support JsonNode surface = writeTerrainLevel(0); @@ -1297,12 +1300,14 @@ void CMapSaverJson::writeTerrain() void CMapSaverJson::writeObjects() { + logGlobal->trace("Saving objects"); JsonNode data(JsonNode::DATA_STRUCT); JsonSerializer handler(mapObjectResolver.get(), data); for(CGObjectInstance * obj : map->objects) { + logGlobal->trace("\t%s", obj->instanceName); auto temp = handler.enterStruct(obj->instanceName); obj->serializeJson(handler);