MapFormatJson.cpp 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  1. /*
  2. * MapFormatJson.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "MapFormatJson.h"
  12. #include "../filesystem/CInputStream.h"
  13. #include "../filesystem/COutputStream.h"
  14. #include "CMap.h"
  15. #include "../CModHandler.h"
  16. #include "../CHeroHandler.h"
  17. #include "../CTownHandler.h"
  18. #include "../VCMI_Lib.h"
  19. #include "../mapObjects/ObjectTemplate.h"
  20. #include "../mapObjects/CObjectHandler.h"
  21. #include "../mapObjects/CObjectClassesHandler.h"
  22. #include "../mapObjects/CGHeroInstance.h"
  23. #include "../mapObjects/CGTownInstance.h"
  24. #include "../spells/CSpellHandler.h"
  25. #include "../StringConstants.h"
  26. #include "../serializer/JsonDeserializer.h"
  27. #include "../serializer/JsonSerializer.h"
  28. namespace HeaderDetail
  29. {
  30. static const ui8 difficultyDefault = 1;//normal
  31. static const std::vector<std::string> difficultyMap =
  32. {
  33. "EASY",
  34. "NORMAL",
  35. "HARD",
  36. "EXPERT",
  37. "IMPOSSIBLE"
  38. };
  39. }
  40. namespace TriggeredEventsDetail
  41. {
  42. static const std::array<std::string, 12> conditionNames =
  43. {
  44. "haveArtifact", "haveCreatures", "haveResources", "haveBuilding",
  45. "control", "destroy", "transport", "daysPassed",
  46. "isHuman", "daysWithoutTown", "standardWin", "constValue"
  47. };
  48. static const std::array<std::string, 2> typeNames = { "victory", "defeat" };
  49. static EventCondition JsonToCondition(const JsonNode & node)
  50. {
  51. //todo: support of new condition format
  52. EventCondition event;
  53. const auto & conditionName = node.Vector()[0].String();
  54. auto pos = vstd::find_pos(conditionNames, conditionName);
  55. event.condition = EventCondition::EWinLoseType(pos);
  56. if (node.Vector().size() > 1)
  57. {
  58. const JsonNode & data = node.Vector()[1];
  59. if (data["type"].getType() == JsonNode::DATA_STRING)
  60. {
  61. auto identifier = VLC->modh->identifiers.getIdentifier(data["type"]);
  62. if(identifier)
  63. event.objectType = identifier.get();
  64. else
  65. throw std::runtime_error("Identifier resolution failed in event condition");
  66. }
  67. if (data["type"].getType() == JsonNode::DATA_FLOAT)
  68. event.objectType = data["type"].Float();
  69. if (!data["value"].isNull())
  70. event.value = data["value"].Float();
  71. if (!data["position"].isNull())
  72. {
  73. auto & position = data["position"].Vector();
  74. event.position.x = position.at(0).Float();
  75. event.position.y = position.at(1).Float();
  76. event.position.z = position.at(2).Float();
  77. }
  78. }
  79. return event;
  80. }
  81. static JsonNode ConditionToJson(const EventCondition& event)
  82. {
  83. JsonNode json;
  84. JsonVector& asVector = json.Vector();
  85. JsonNode condition;
  86. condition.String() = conditionNames.at(event.condition);
  87. asVector.push_back(condition);
  88. JsonNode data;
  89. //todo: save identifier
  90. if(event.objectType != -1)
  91. data["type"].Float() = event.objectType;
  92. if(event.value != -1)
  93. data["value"].Float() = event.value;
  94. if(event.position != int3(-1,-1,-1))
  95. {
  96. auto & position = data["position"].Vector();
  97. position.resize(3);
  98. position[0].Float() = event.position.x;
  99. position[1].Float() = event.position.y;
  100. position[2].Float() = event.position.z;
  101. }
  102. if(!data.isNull())
  103. asVector.push_back(data);
  104. return std::move(json);
  105. }
  106. }//namespace TriggeredEventsDetail
  107. namespace TerrainDetail
  108. {
  109. static const std::array<std::string, 10> terrainCodes =
  110. {
  111. "dt", "sa", "gr", "sn", "sw", "rg", "sb", "lv", "wt", "rc"
  112. };
  113. static const std::array<std::string, 4> roadCodes =
  114. {
  115. "", "pd", "pg", "pc"
  116. };
  117. static const std::array<std::string, 5> riverCodes =
  118. {
  119. "", "rw", "ri", "rm", "rl"
  120. };
  121. static const std::array<char, 10> flipCodes =
  122. {
  123. '_', '-', '|', '+'
  124. };
  125. }
  126. static std::string tailString(const std::string & input, char separator)
  127. {
  128. std::string ret;
  129. size_t splitPos = input.find(separator);
  130. if (splitPos != std::string::npos)
  131. ret = input.substr(splitPos + 1);
  132. return ret;
  133. }
  134. static si32 extractNumber(const std::string & input, char separator)
  135. {
  136. std::string tmp = tailString(input, separator);
  137. return atoi(tmp.c_str());
  138. }
  139. ///CMapFormatJson
  140. const int CMapFormatJson::VERSION_MAJOR = 1;
  141. const int CMapFormatJson::VERSION_MINOR = 0;
  142. const std::string CMapFormatJson::HEADER_FILE_NAME = "header.json";
  143. const std::string CMapFormatJson::OBJECTS_FILE_NAME = "objects.json";
  144. void CMapFormatJson::serializeAllowedFactions(JsonSerializeFormat & handler, std::set<TFaction> & value)
  145. {
  146. //TODO: unify allowed factions with others - make them std::vector<bool>
  147. std::vector<bool> temp;
  148. temp.resize(VLC->townh->factions.size(), false);
  149. auto standard = VLC->townh->getDefaultAllowed();
  150. if(handler.saving)
  151. {
  152. for(auto faction : VLC->townh->factions)
  153. if(faction->town && vstd::contains(value, faction->index))
  154. temp[std::size_t(faction->index)] = true;
  155. }
  156. handler.serializeLIC("allowedFactions", &CTownHandler::decodeFaction, &CTownHandler::encodeFaction, standard, temp);
  157. if(!handler.saving)
  158. {
  159. value.clear();
  160. for (std::size_t i=0; i<temp.size(); i++)
  161. if(temp[i])
  162. value.insert(i);
  163. }
  164. }
  165. void CMapFormatJson::serializeHeader(JsonSerializeFormat & handler)
  166. {
  167. handler.serializeString("name", mapHeader->name);
  168. handler.serializeString("description", mapHeader->description);
  169. handler.serializeNumeric("heroLevelLimit", mapHeader->levelLimit);
  170. //todo: support arbitrary percentage
  171. handler.serializeNumericEnum("difficulty", HeaderDetail::difficultyMap, HeaderDetail::difficultyDefault, mapHeader->difficulty);
  172. serializePlayerInfo(handler);
  173. handler.serializeLIC("allowedHeroes", &CHeroHandler::decodeHero, &CHeroHandler::encodeHero, VLC->heroh->getDefaultAllowed(), mapHeader->allowedHeroes);
  174. }
  175. void CMapFormatJson::serializePlayerInfo(JsonSerializeFormat & handler)
  176. {
  177. auto playersData = handler.enterStruct("players");
  178. for(int player = 0; player < PlayerColor::PLAYER_LIMIT_I; player++)
  179. {
  180. PlayerInfo & info = mapHeader->players[player];
  181. if(handler.saving)
  182. {
  183. if(!info.canAnyonePlay())
  184. continue;
  185. }
  186. auto playerData = playersData.enterStruct(GameConstants::PLAYER_COLOR_NAMES[player]);
  187. if(!handler.saving)
  188. {
  189. if(playerData.get().isNull())
  190. {
  191. info.canComputerPlay = false;
  192. info.canHumanPlay = false;
  193. continue;
  194. }
  195. info.canComputerPlay = true;
  196. }
  197. serializeAllowedFactions(handler, info.allowedFactions);
  198. handler.serializeBoolEnum("canPlay", "PlayerOrAI", "AIOnly", info.canHumanPlay);
  199. //mainTown
  200. if(handler.saving)
  201. {
  202. }
  203. else
  204. {
  205. }
  206. handler.serializeBool("generateHeroAtMainTown", info.generateHeroAtMainTown);
  207. //mainHero
  208. //mainHeroPortrait
  209. //mainCustomHeroName
  210. //towns
  211. //heroes
  212. {
  213. //auto heroes = playerData.enterStruct("heroes");
  214. }
  215. if(!handler.saving)
  216. {
  217. //isFactionRandom indicates that player may select faction, depends on towns & heroes
  218. // true if main town is random and generateHeroAtMainTown==true
  219. // or main hero is random
  220. //TODO: recheck mechanics
  221. // info.isFactionRandom =
  222. }
  223. }
  224. }
  225. void CMapFormatJson::readTeams(JsonDeserializer & handler)
  226. {
  227. auto teams = handler.enterStruct("teams");
  228. const JsonNode & src = teams.get();
  229. if(src.getType() != JsonNode::DATA_VECTOR)
  230. {
  231. // No alliances
  232. if(src.getType() != JsonNode::DATA_NULL)
  233. logGlobal->errorStream() << "Invalid teams field type";
  234. mapHeader->howManyTeams = 0;
  235. for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++)
  236. {
  237. if(mapHeader->players[i].canComputerPlay || mapHeader->players[i].canHumanPlay)
  238. {
  239. mapHeader->players[i].team = TeamID(mapHeader->howManyTeams++);
  240. }
  241. }
  242. }
  243. else
  244. {
  245. const JsonVector & srcVector = src.Vector();
  246. mapHeader->howManyTeams = srcVector.size();
  247. for(int team = 0; team < mapHeader->howManyTeams; team++)
  248. {
  249. for(const JsonNode & playerData : srcVector[team].Vector())
  250. {
  251. PlayerColor player = PlayerColor(vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, playerData.String()));
  252. if(player.isValidPlayer())
  253. {
  254. if(mapHeader->players[player.getNum()].canAnyonePlay())
  255. {
  256. mapHeader->players[player.getNum()].team = TeamID(team);
  257. }
  258. }
  259. }
  260. }
  261. for(PlayerInfo & player : mapHeader->players)
  262. {
  263. if(player.canAnyonePlay() && player.team == TeamID::NO_TEAM)
  264. player.team = TeamID(mapHeader->howManyTeams++);
  265. }
  266. }
  267. }
  268. void CMapFormatJson::writeTeams(JsonSerializer & handler)
  269. {
  270. auto teams = handler.enterStruct("teams");
  271. JsonNode & dest = teams.get();
  272. std::vector<std::set<PlayerColor>> teamsData;
  273. teamsData.resize(mapHeader->howManyTeams);
  274. //get raw data
  275. for(int idx = 0; idx < mapHeader->players.size(); idx++)
  276. {
  277. const PlayerInfo & player = mapHeader->players.at(idx);
  278. int team = player.team.getNum();
  279. if(vstd::iswithin(team, 0, mapHeader->howManyTeams-1) && player.canAnyonePlay())
  280. teamsData.at(team).insert(PlayerColor(idx));
  281. }
  282. //remove single-member teams
  283. vstd::erase_if(teamsData, [](std::set<PlayerColor> & elem) -> bool
  284. {
  285. return elem.size() <= 1;
  286. });
  287. //construct output
  288. dest.setType(JsonNode::DATA_VECTOR);
  289. for(const std::set<PlayerColor> & teamData : teamsData)
  290. {
  291. JsonNode team(JsonNode::DATA_VECTOR);
  292. for(const PlayerColor & player : teamData)
  293. {
  294. JsonNode member(JsonNode::DATA_STRING);
  295. member.String() = GameConstants::PLAYER_COLOR_NAMES[player.getNum()];
  296. team.Vector().push_back(std::move(member));
  297. }
  298. dest.Vector().push_back(std::move(team));
  299. }
  300. }
  301. void CMapFormatJson::serializeTriggeredEvents(JsonSerializeFormat & handler)
  302. {
  303. handler.serializeString("victoryString", mapHeader->victoryMessage);
  304. handler.serializeNumeric("victoryIconIndex", mapHeader->victoryIconIndex);
  305. handler.serializeString("defeatString", mapHeader->defeatMessage);
  306. handler.serializeNumeric("defeatIconIndex", mapHeader->defeatIconIndex);
  307. }
  308. void CMapFormatJson::readTriggeredEvents(JsonDeserializer & handler)
  309. {
  310. const JsonNode & input = handler.getCurrent();
  311. serializeTriggeredEvents(handler);
  312. mapHeader->triggeredEvents.clear();
  313. for (auto & entry : input["triggeredEvents"].Struct())
  314. {
  315. TriggeredEvent event;
  316. event.identifier = entry.first;
  317. readTriggeredEvent(event, entry.second);
  318. mapHeader->triggeredEvents.push_back(event);
  319. }
  320. }
  321. void CMapFormatJson::readTriggeredEvent(TriggeredEvent & event, const JsonNode & source)
  322. {
  323. using namespace TriggeredEventsDetail;
  324. event.onFulfill = source["message"].String();
  325. event.description = source["description"].String();
  326. event.effect.type = vstd::find_pos(typeNames, source["effect"]["type"].String());
  327. event.effect.toOtherMessage = source["effect"]["messageToSend"].String();
  328. event.trigger = EventExpression(source["condition"], JsonToCondition); // logical expression
  329. }
  330. void CMapFormatJson::writeTriggeredEvents(JsonSerializer & handler)
  331. {
  332. JsonNode & output = handler.getCurrent();
  333. serializeTriggeredEvents(handler);
  334. JsonMap & triggeredEvents = output["triggeredEvents"].Struct();
  335. for(auto event : mapHeader->triggeredEvents)
  336. writeTriggeredEvent(event, triggeredEvents[event.identifier]);
  337. }
  338. void CMapFormatJson::writeTriggeredEvent(const TriggeredEvent& event, JsonNode& dest)
  339. {
  340. using namespace TriggeredEventsDetail;
  341. dest["message"].String() = event.onFulfill;
  342. dest["description"].String() = event.description;
  343. dest["effect"]["type"].String() = typeNames.at(size_t(event.effect.type));
  344. dest["effect"]["messageToSend"].String() = event.effect.toOtherMessage;
  345. dest["condition"] = event.trigger.toJson(ConditionToJson);
  346. }
  347. void CMapFormatJson::serializeOptions(JsonSerializeFormat & handler)
  348. {
  349. //rumors
  350. //disposedHeroes
  351. //predefinedHeroes
  352. handler.serializeLIC("allowedAbilities", &CHeroHandler::decodeSkill, &CHeroHandler::encodeSkill, VLC->heroh->getDefaultAllowedAbilities(), map->allowedAbilities);
  353. handler.serializeLIC("allowedArtifacts", &CArtHandler::decodeArfifact, &CArtHandler::encodeArtifact, VLC->arth->getDefaultAllowed(), map->allowedArtifact);
  354. handler.serializeLIC("allowedSpells", &CSpellHandler::decodeSpell, &CSpellHandler::encodeSpell, VLC->spellh->getDefaultAllowed(), map->allowedSpell);
  355. //events
  356. }
  357. void CMapFormatJson::readOptions(JsonDeserializer & handler)
  358. {
  359. serializeOptions(handler);
  360. }
  361. void CMapFormatJson::writeOptions(JsonSerializer & handler)
  362. {
  363. serializeOptions(handler);
  364. }
  365. ///CMapPatcher
  366. CMapPatcher::CMapPatcher(JsonNode stream):
  367. input(stream)
  368. {
  369. }
  370. void CMapPatcher::patchMapHeader(std::unique_ptr<CMapHeader> & header)
  371. {
  372. map = nullptr;
  373. mapHeader = header.get();
  374. if (!input.isNull())
  375. readPatchData();
  376. }
  377. void CMapPatcher::readPatchData()
  378. {
  379. JsonDeserializer handler(input);
  380. readTriggeredEvents(handler);
  381. }
  382. ///CMapLoaderJson
  383. CMapLoaderJson::CMapLoaderJson(CInputStream * stream):
  384. buffer(stream),
  385. ioApi(new CProxyROIOApi(buffer)),
  386. loader("", "_", ioApi)
  387. {
  388. }
  389. si32 CMapLoaderJson::getIdentifier(const std::string& type, const std::string& name)
  390. {
  391. boost::optional<si32> res = VLC->modh->identifiers.getIdentifier("core", type, name, false);
  392. if(!res)
  393. {
  394. throw new std::runtime_error("Map load failed. Identifier not resolved.");
  395. }
  396. return res.get();
  397. }
  398. std::unique_ptr<CMap> CMapLoaderJson::loadMap()
  399. {
  400. LOG_TRACE(logGlobal);
  401. std::unique_ptr<CMap> result = std::unique_ptr<CMap>(new CMap());
  402. map = result.get();
  403. mapHeader = map;
  404. readMap();
  405. return std::move(result);
  406. }
  407. std::unique_ptr<CMapHeader> CMapLoaderJson::loadMapHeader()
  408. {
  409. LOG_TRACE(logGlobal);
  410. map = nullptr;
  411. std::unique_ptr<CMapHeader> result = std::unique_ptr<CMapHeader>(new CMapHeader());
  412. mapHeader = result.get();
  413. readHeader(false);
  414. return std::move(result);
  415. }
  416. JsonNode CMapLoaderJson::getFromArchive(const std::string & archiveFilename)
  417. {
  418. ResourceID resource(archiveFilename, EResType::TEXT);
  419. if(!loader.existsResource(resource))
  420. throw new std::runtime_error(archiveFilename+" not found");
  421. auto data = loader.load(resource)->readAll();
  422. JsonNode res(reinterpret_cast<char*>(data.first.get()), data.second);
  423. return std::move(res);
  424. }
  425. void CMapLoaderJson::readMap()
  426. {
  427. LOG_TRACE(logGlobal);
  428. readHeader(true);
  429. map->initTerrain();
  430. readTerrain();
  431. readObjects();
  432. // Calculate blocked / visitable positions
  433. for(auto & elem : map->objects)
  434. {
  435. map->addBlockVisTiles(elem);
  436. }
  437. map->calculateGuardingGreaturePositions();
  438. }
  439. void CMapLoaderJson::readHeader(const bool complete)
  440. {
  441. //do not use map field here, use only mapHeader
  442. JsonNode header = getFromArchive(HEADER_FILE_NAME);
  443. int versionMajor = header["versionMajor"].Float();
  444. if(versionMajor != VERSION_MAJOR)
  445. {
  446. logGlobal->errorStream() << "Unsupported map format version: " << versionMajor;
  447. throw std::runtime_error("Unsupported map format version");
  448. }
  449. int versionMinor = header["versionMinor"].Float();
  450. if(versionMinor > VERSION_MINOR)
  451. {
  452. logGlobal->traceStream() << "Too new map format revision: " << versionMinor << ". This map should work but some of map features may be ignored.";
  453. }
  454. JsonDeserializer handler(header);
  455. mapHeader->version = EMapFormat::VCMI;//todo: new version field
  456. //todo: multilevel map load support
  457. {
  458. auto levels = handler.enterStruct("mapLevels");
  459. {
  460. auto surface = levels.enterStruct("surface");
  461. mapHeader->height = surface.get()["height"].Float();
  462. mapHeader->width = surface.get()["width"].Float();
  463. }
  464. {
  465. auto underground = levels.enterStruct("underground");
  466. mapHeader->twoLevel = !underground.get().isNull();
  467. }
  468. }
  469. serializeHeader(handler);
  470. readTriggeredEvents(handler);
  471. readTeams(handler);
  472. //TODO: readHeader
  473. if(complete)
  474. readOptions(handler);
  475. }
  476. void CMapLoaderJson::readTerrainTile(const std::string& src, TerrainTile& tile)
  477. {
  478. using namespace TerrainDetail;
  479. {//terrain type
  480. const std::string typeCode = src.substr(0,2);
  481. int rawType = vstd::find_pos(terrainCodes, typeCode);
  482. if(rawType < 0)
  483. throw new std::runtime_error("Invalid terrain type code in "+src);
  484. tile.terType = ETerrainType(rawType);
  485. }
  486. int startPos = 2; //0+typeCode fixed length
  487. {//terrain view
  488. int pos = startPos;
  489. while(isdigit(src.at(pos)))
  490. pos++;
  491. int len = pos - startPos;
  492. if(len<=0)
  493. throw new std::runtime_error("Invalid terrain view in "+src);
  494. const std::string rawCode = src.substr(startPos,len);
  495. tile.terView = atoi(rawCode.c_str());
  496. startPos+=len;
  497. }
  498. {//terrain flip
  499. int terrainFlip = vstd::find_pos(flipCodes, src.at(startPos++));
  500. if(terrainFlip < 0)
  501. throw new std::runtime_error("Invalid terrain flip in "+src);
  502. else
  503. tile.extTileFlags = terrainFlip;
  504. }
  505. if(startPos >= src.size())
  506. return;
  507. bool hasRoad = true;
  508. {//road type
  509. const std::string typeCode = src.substr(startPos,2);
  510. startPos+=2;
  511. int rawType = vstd::find_pos(roadCodes, typeCode);
  512. if(rawType < 0)
  513. {
  514. rawType = vstd::find_pos(riverCodes, typeCode);
  515. if(rawType < 0)
  516. throw new std::runtime_error("Invalid river type in "+src);
  517. else
  518. {
  519. tile.riverType = ERiverType::ERiverType(rawType);
  520. hasRoad = false;
  521. }
  522. }
  523. else
  524. tile.roadType = ERoadType::ERoadType(rawType);
  525. }
  526. if(hasRoad)
  527. {//road dir
  528. int pos = startPos;
  529. while(isdigit(src.at(pos)))
  530. pos++;
  531. int len = pos - startPos;
  532. if(len<=0)
  533. throw new std::runtime_error("Invalid road dir in "+src);
  534. const std::string rawCode = src.substr(startPos,len);
  535. tile.roadDir = atoi(rawCode.c_str());
  536. startPos+=len;
  537. }
  538. if(hasRoad)
  539. {//road flip
  540. int flip = vstd::find_pos(flipCodes, src.at(startPos++));
  541. if(flip < 0)
  542. throw new std::runtime_error("Invalid road flip in "+src);
  543. else
  544. tile.extTileFlags |= (flip<<4);
  545. }
  546. if(startPos >= src.size())
  547. return;
  548. if(hasRoad)
  549. {//river type
  550. const std::string typeCode = src.substr(startPos,2);
  551. startPos+=2;
  552. int rawType = vstd::find_pos(riverCodes, typeCode);
  553. if(rawType < 0)
  554. throw new std::runtime_error("Invalid river type in "+src);
  555. tile.riverType = ERiverType::ERiverType(rawType);
  556. }
  557. {//river dir
  558. int pos = startPos;
  559. while(isdigit(src.at(pos)))
  560. pos++;
  561. int len = pos - startPos;
  562. if(len<=0)
  563. throw new std::runtime_error("Invalid river dir in "+src);
  564. const std::string rawCode = src.substr(startPos,len);
  565. tile.riverDir = atoi(rawCode.c_str());
  566. startPos+=len;
  567. }
  568. {//river flip
  569. int flip = vstd::find_pos(flipCodes, src.at(startPos++));
  570. if(flip < 0)
  571. throw new std::runtime_error("Invalid road flip in "+src);
  572. else
  573. tile.extTileFlags |= (flip<<2);
  574. }
  575. }
  576. void CMapLoaderJson::readTerrainLevel(const JsonNode& src, const int index)
  577. {
  578. int3 pos(0,0,index);
  579. const JsonVector & rows = src.Vector();
  580. if(rows.size() != map->height)
  581. throw new std::runtime_error("Invalid terrain data");
  582. for(pos.y = 0; pos.y < map->height; pos.y++)
  583. {
  584. const JsonVector & tiles = rows[pos.y].Vector();
  585. if(tiles.size() != map->width)
  586. throw new std::runtime_error("Invalid terrain data");
  587. for(pos.x = 0; pos.x < map->width; pos.x++)
  588. readTerrainTile(tiles[pos.x].String(), map->getTile(pos));
  589. }
  590. }
  591. void CMapLoaderJson::readTerrain()
  592. {
  593. {
  594. const JsonNode surface = getFromArchive("surface_terrain.json");
  595. readTerrainLevel(surface, 0);
  596. }
  597. if(map->twoLevel)
  598. {
  599. const JsonNode underground = getFromArchive("underground_terrain.json");
  600. readTerrainLevel(underground, 1);
  601. }
  602. }
  603. CMapLoaderJson::MapObjectLoader::MapObjectLoader(CMapLoaderJson * _owner, JsonMap::value_type& json):
  604. owner(_owner), instance(nullptr),id(-1), jsonKey(json.first), configuration(json.second), internalId(extractNumber(jsonKey, '_'))
  605. {
  606. }
  607. void CMapLoaderJson::MapObjectLoader::construct()
  608. {
  609. logGlobal->debugStream() <<"Loading: " <<jsonKey;
  610. //TODO:consider move to ObjectTypeHandler
  611. //find type handler
  612. std::string typeName = configuration["type"].String(), subTypeName = configuration["subType"].String();
  613. if(typeName.empty())
  614. {
  615. logGlobal->errorStream() << "Object type missing";
  616. logGlobal->traceStream() << configuration;
  617. return;
  618. }
  619. //special case for grail
  620. if(typeName == "grail")
  621. {
  622. auto & pos = owner->map->grailPos;
  623. pos.x = configuration["x"].Float();
  624. pos.y = configuration["y"].Float();
  625. pos.z = configuration["l"].Float();
  626. owner->map->grailRadius = configuration["options"]["grailRadius"].Float();
  627. return;
  628. }
  629. else if(subTypeName.empty())
  630. {
  631. logGlobal->errorStream() << "Object subType missing";
  632. logGlobal->traceStream() << configuration;
  633. return;
  634. }
  635. auto handler = VLC->objtypeh->getHandlerFor(typeName, subTypeName);
  636. instance = handler->create(ObjectTemplate());
  637. instance->id = ObjectInstanceID(owner->map->objects.size());
  638. owner->map->objects.push_back(instance);
  639. }
  640. void CMapLoaderJson::MapObjectLoader::configure()
  641. {
  642. if(nullptr == instance)
  643. return;
  644. JsonDeserializer handler(configuration);
  645. instance->serializeJson(handler);
  646. if(instance->ID == Obj::TOWN)
  647. {
  648. owner->map->towns.push_back(static_cast<CGTownInstance *>(instance));
  649. }
  650. else if(instance->ID == Obj::HERO)
  651. {
  652. logGlobal->debugStream() << "Hero: " << VLC->heroh->heroes[instance->subID]->name << " at " << instance->pos;
  653. owner->map->heroesOnMap.push_back(static_cast<CGHeroInstance *>(instance));
  654. }
  655. else if(auto art = dynamic_cast<CGArtifact *>(instance))
  656. {
  657. //todo: find better place for this code
  658. int artID = ArtifactID::NONE;
  659. int spellID = -1;
  660. if(art->ID == Obj::SPELL_SCROLL)
  661. {
  662. auto spellIdentifier = configuration["options"]["spell"].String();
  663. auto rawId = VLC->modh->identifiers.getIdentifier("core", "spell", spellIdentifier);
  664. if(rawId)
  665. spellID = rawId.get();
  666. else
  667. spellID = 0;
  668. artID = ArtifactID::SPELL_SCROLL;
  669. }
  670. else if(art->ID == Obj::ARTIFACT)
  671. {
  672. //specific artifact
  673. artID = art->subID;
  674. }
  675. art->storedArtifact = CArtifactInstance::createArtifact(owner->map, artID, spellID);
  676. }
  677. }
  678. void CMapLoaderJson::readObjects()
  679. {
  680. LOG_TRACE(logGlobal);
  681. std::vector<std::unique_ptr<MapObjectLoader>> loaders;//todo: optimize MapObjectLoader memory layout
  682. JsonNode data = getFromArchive(OBJECTS_FILE_NAME);
  683. //get raw data
  684. for(auto & p : data.Struct())
  685. loaders.push_back(vstd::make_unique<MapObjectLoader>(this, p));
  686. auto sortInfos = [](const std::unique_ptr<MapObjectLoader> & lhs, const std::unique_ptr<MapObjectLoader> & rhs) -> bool
  687. {
  688. return lhs->internalId < rhs->internalId;
  689. };
  690. boost::sort(loaders, sortInfos);//this makes instance ids consistent after save-load, needed for testing
  691. //todo: use internalId in CMap
  692. for(auto & ptr : loaders)
  693. ptr->construct();
  694. //configure objects after all objects are constructed so we may resolve internal IDs even to actual pointers OTF
  695. for(auto & ptr : loaders)
  696. ptr->configure();
  697. }
  698. ///CMapSaverJson
  699. CMapSaverJson::CMapSaverJson(CInputOutputStream * stream):
  700. buffer(stream),
  701. ioApi(new CProxyIOApi(buffer)),
  702. saver(ioApi, "_")
  703. {
  704. }
  705. CMapSaverJson::~CMapSaverJson()
  706. {
  707. }
  708. void CMapSaverJson::addToArchive(const JsonNode& data, const std::string& filename)
  709. {
  710. std::ostringstream out;
  711. out << data;
  712. out.flush();
  713. {
  714. auto s = out.str();
  715. std::unique_ptr<COutputStream> stream = saver.addFile(filename);
  716. if (stream->write((const ui8*)s.c_str(), s.size()) != s.size())
  717. throw new std::runtime_error("CMapSaverJson::saveHeader() zip compression failed.");
  718. }
  719. }
  720. void CMapSaverJson::saveMap(const std::unique_ptr<CMap>& map)
  721. {
  722. this->map = map.get();
  723. this->mapHeader = this->map;
  724. writeHeader();
  725. writeTerrain();
  726. writeObjects();
  727. }
  728. void CMapSaverJson::writeHeader()
  729. {
  730. JsonNode header;
  731. JsonSerializer handler(header);
  732. header["versionMajor"].Float() = VERSION_MAJOR;
  733. header["versionMinor"].Float() = VERSION_MINOR;
  734. //todo: multilevel map save support
  735. JsonNode & levels = header["mapLevels"];
  736. levels["surface"]["height"].Float() = mapHeader->height;
  737. levels["surface"]["width"].Float() = mapHeader->width;
  738. levels["surface"]["index"].Float() = 0;
  739. if(mapHeader->twoLevel)
  740. {
  741. levels["underground"]["height"].Float() = mapHeader->height;
  742. levels["underground"]["width"].Float() = mapHeader->width;
  743. levels["underground"]["index"].Float() = 1;
  744. }
  745. serializeHeader(handler);
  746. writeTriggeredEvents(handler);
  747. writeTeams(handler);
  748. writeOptions(handler);
  749. addToArchive(header, HEADER_FILE_NAME);
  750. }
  751. const std::string CMapSaverJson::writeTerrainTile(const TerrainTile & tile)
  752. {
  753. using namespace TerrainDetail;
  754. std::ostringstream out;
  755. out.setf(std::ios::dec, std::ios::basefield);
  756. out.unsetf(std::ios::showbase);
  757. out << terrainCodes.at(int(tile.terType)) << (int)tile.terView << flipCodes[tile.extTileFlags % 4];
  758. if(tile.roadType != ERoadType::NO_ROAD)
  759. {
  760. out << roadCodes.at(int(tile.roadType)) << (int)tile.roadDir << flipCodes[(tile.extTileFlags >> 4) % 4];
  761. }
  762. if(tile.riverType != ERiverType::NO_RIVER)
  763. {
  764. out << riverCodes.at(int(tile.riverType)) << (int)tile.riverDir << flipCodes[(tile.extTileFlags >> 2) % 4];
  765. }
  766. return out.str();
  767. }
  768. JsonNode CMapSaverJson::writeTerrainLevel(const int index)
  769. {
  770. JsonNode data;
  771. int3 pos(0,0,index);
  772. data.Vector().resize(map->height);
  773. for(pos.y = 0; pos.y < map->height; pos.y++)
  774. {
  775. JsonNode & row = data.Vector()[pos.y];
  776. row.Vector().resize(map->width);
  777. for(pos.x = 0; pos.x < map->width; pos.x++)
  778. row.Vector()[pos.x].String() = writeTerrainTile(map->getTile(pos));
  779. }
  780. return std::move(data);
  781. }
  782. void CMapSaverJson::writeTerrain()
  783. {
  784. //todo: multilevel map save support
  785. JsonNode surface = writeTerrainLevel(0);
  786. addToArchive(surface, "surface_terrain.json");
  787. if(map->twoLevel)
  788. {
  789. JsonNode underground = writeTerrainLevel(1);
  790. addToArchive(underground, "underground_terrain.json");
  791. }
  792. }
  793. void CMapSaverJson::writeObjects()
  794. {
  795. JsonNode data(JsonNode::DATA_STRUCT);
  796. JsonSerializer handler(data);
  797. for(CGObjectInstance * obj : map->objects)
  798. {
  799. auto temp = handler.enterStruct(obj->getStringId());
  800. obj->serializeJson(handler);
  801. }
  802. if(map->grailPos.valid())
  803. {
  804. JsonNode grail(JsonNode::DATA_STRUCT);
  805. grail["type"].String() = "grail";
  806. grail["x"].Float() = map->grailPos.x;
  807. grail["y"].Float() = map->grailPos.y;
  808. grail["l"].Float() = map->grailPos.z;
  809. grail["options"]["radius"].Float() = map->grailRadius;
  810. std::string grailId = boost::str(boost::format("grail_%d") % map->objects.size());
  811. data[grailId] = grail;
  812. }
  813. addToArchive(data, OBJECTS_FILE_NAME);
  814. }