mg_schematic.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. /*
  2. Minetest
  3. Copyright (C) 2014-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
  4. Copyright (C) 2015-2018 paramat
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation; either version 2.1 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License along
  14. with this program; if not, write to the Free Software Foundation, Inc.,
  15. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  16. */
  17. #include <fstream>
  18. #include <typeinfo>
  19. #include "mg_schematic.h"
  20. #include "server.h"
  21. #include "mapgen.h"
  22. #include "emerge.h"
  23. #include "map.h"
  24. #include "mapblock.h"
  25. #include "log.h"
  26. #include "util/numeric.h"
  27. #include "util/serialize.h"
  28. #include "serialization.h"
  29. #include "filesys.h"
  30. #include "voxelalgorithms.h"
  31. ///////////////////////////////////////////////////////////////////////////////
  32. SchematicManager::SchematicManager(Server *server) :
  33. ObjDefManager(server, OBJDEF_SCHEMATIC),
  34. m_server(server)
  35. {
  36. }
  37. SchematicManager *SchematicManager::clone() const
  38. {
  39. auto mgr = new SchematicManager();
  40. assert(mgr);
  41. ObjDefManager::cloneTo(mgr);
  42. return mgr;
  43. }
  44. void SchematicManager::clear()
  45. {
  46. EmergeManager *emerge = m_server->getEmergeManager();
  47. // Remove all dangling references in Decorations
  48. DecorationManager *decomgr = emerge->getWritableDecorationManager();
  49. for (size_t i = 0; i != decomgr->getNumObjects(); i++) {
  50. Decoration *deco = (Decoration *)decomgr->getRaw(i);
  51. try {
  52. DecoSchematic *dschem = dynamic_cast<DecoSchematic *>(deco);
  53. if (dschem)
  54. dschem->schematic = NULL;
  55. } catch (const std::bad_cast &) {
  56. }
  57. }
  58. ObjDefManager::clear();
  59. }
  60. ///////////////////////////////////////////////////////////////////////////////
  61. Schematic::~Schematic()
  62. {
  63. delete []schemdata;
  64. delete []slice_probs;
  65. }
  66. ObjDef *Schematic::clone() const
  67. {
  68. auto def = new Schematic();
  69. ObjDef::cloneTo(def);
  70. NodeResolver::cloneTo(def);
  71. def->c_nodes = c_nodes;
  72. def->flags = flags;
  73. def->size = size;
  74. FATAL_ERROR_IF(!schemdata, "Schematic can only be cloned after loading");
  75. u32 nodecount = size.X * size.Y * size.Z;
  76. def->schemdata = new MapNode[nodecount];
  77. memcpy(def->schemdata, schemdata, sizeof(MapNode) * nodecount);
  78. def->slice_probs = new u8[size.Y];
  79. memcpy(def->slice_probs, slice_probs, sizeof(u8) * size.Y);
  80. return def;
  81. }
  82. void Schematic::resolveNodeNames()
  83. {
  84. c_nodes.clear();
  85. getIdsFromNrBacklog(&c_nodes, true, CONTENT_AIR);
  86. size_t bufsize = size.X * size.Y * size.Z;
  87. for (size_t i = 0; i != bufsize; i++) {
  88. content_t c_original = schemdata[i].getContent();
  89. if (c_original >= c_nodes.size()) {
  90. errorstream << "Corrupt schematic. name=\"" << name
  91. << "\" at index " << i << std::endl;
  92. c_original = 0;
  93. }
  94. // Unfold condensed ID layout to content_t
  95. schemdata[i].setContent(c_nodes[c_original]);
  96. }
  97. }
  98. void Schematic::blitToVManip(MMVManip *vm, v3s16 p, Rotation rot, bool force_place)
  99. {
  100. assert(schemdata && slice_probs);
  101. sanity_check(m_ndef != NULL);
  102. int xstride = 1;
  103. int ystride = size.X;
  104. int zstride = size.X * size.Y;
  105. s16 sx = size.X;
  106. s16 sy = size.Y;
  107. s16 sz = size.Z;
  108. int i_start, i_step_x, i_step_z;
  109. switch (rot) {
  110. case ROTATE_90:
  111. i_start = sx - 1;
  112. i_step_x = zstride;
  113. i_step_z = -xstride;
  114. SWAP(s16, sx, sz);
  115. break;
  116. case ROTATE_180:
  117. i_start = zstride * (sz - 1) + sx - 1;
  118. i_step_x = -xstride;
  119. i_step_z = -zstride;
  120. break;
  121. case ROTATE_270:
  122. i_start = zstride * (sz - 1);
  123. i_step_x = -zstride;
  124. i_step_z = xstride;
  125. SWAP(s16, sx, sz);
  126. break;
  127. default:
  128. i_start = 0;
  129. i_step_x = xstride;
  130. i_step_z = zstride;
  131. }
  132. s16 y_map = p.Y;
  133. for (s16 y = 0; y != sy; y++) {
  134. if ((slice_probs[y] != MTSCHEM_PROB_ALWAYS) &&
  135. (slice_probs[y] <= myrand_range(1, MTSCHEM_PROB_ALWAYS)))
  136. continue;
  137. for (s16 z = 0; z != sz; z++) {
  138. u32 i = z * i_step_z + y * ystride + i_start;
  139. for (s16 x = 0; x != sx; x++, i += i_step_x) {
  140. v3s16 pos(p.X + x, y_map, p.Z + z);
  141. if (!vm->m_area.contains(pos))
  142. continue;
  143. if (schemdata[i].getContent() == CONTENT_IGNORE)
  144. continue;
  145. u8 placement_prob = schemdata[i].param1 & MTSCHEM_PROB_MASK;
  146. bool force_place_node = schemdata[i].param1 & MTSCHEM_FORCE_PLACE;
  147. if (placement_prob == MTSCHEM_PROB_NEVER)
  148. continue;
  149. u32 vi = vm->m_area.index(pos);
  150. if (!force_place && !force_place_node) {
  151. content_t c = vm->m_data[vi].getContent();
  152. if (c != CONTENT_AIR && c != CONTENT_IGNORE)
  153. continue;
  154. }
  155. if ((placement_prob != MTSCHEM_PROB_ALWAYS) &&
  156. (placement_prob <= myrand_range(1, MTSCHEM_PROB_ALWAYS)))
  157. continue;
  158. vm->m_data[vi] = schemdata[i];
  159. vm->m_data[vi].param1 = 0;
  160. if (rot)
  161. vm->m_data[vi].rotateAlongYAxis(m_ndef, rot);
  162. }
  163. }
  164. y_map++;
  165. }
  166. }
  167. bool Schematic::placeOnVManip(MMVManip *vm, v3s16 p, u32 flags,
  168. Rotation rot, bool force_place)
  169. {
  170. assert(vm != NULL);
  171. assert(schemdata && slice_probs);
  172. sanity_check(m_ndef != NULL);
  173. //// Determine effective rotation and effective schematic dimensions
  174. if (rot == ROTATE_RAND)
  175. rot = (Rotation)myrand_range(ROTATE_0, ROTATE_270);
  176. v3s16 s = (rot == ROTATE_90 || rot == ROTATE_270) ?
  177. v3s16(size.Z, size.Y, size.X) : size;
  178. //// Adjust placement position if necessary
  179. if (flags & DECO_PLACE_CENTER_X)
  180. p.X -= (s.X - 1) / 2;
  181. if (flags & DECO_PLACE_CENTER_Y)
  182. p.Y -= (s.Y - 1) / 2;
  183. if (flags & DECO_PLACE_CENTER_Z)
  184. p.Z -= (s.Z - 1) / 2;
  185. blitToVManip(vm, p, rot, force_place);
  186. return vm->m_area.contains(VoxelArea(p, p + s - v3s16(1, 1, 1)));
  187. }
  188. void Schematic::placeOnMap(ServerMap *map, v3s16 p, u32 flags,
  189. Rotation rot, bool force_place)
  190. {
  191. std::map<v3s16, MapBlock *> modified_blocks;
  192. std::map<v3s16, MapBlock *>::iterator it;
  193. assert(map != NULL);
  194. assert(schemdata != NULL);
  195. sanity_check(m_ndef != NULL);
  196. //// Determine effective rotation and effective schematic dimensions
  197. if (rot == ROTATE_RAND)
  198. rot = (Rotation)myrand_range(ROTATE_0, ROTATE_270);
  199. v3s16 s = (rot == ROTATE_90 || rot == ROTATE_270) ?
  200. v3s16(size.Z, size.Y, size.X) : size;
  201. //// Adjust placement position if necessary
  202. if (flags & DECO_PLACE_CENTER_X)
  203. p.X -= (s.X - 1) / 2;
  204. if (flags & DECO_PLACE_CENTER_Y)
  205. p.Y -= (s.Y - 1) / 2;
  206. if (flags & DECO_PLACE_CENTER_Z)
  207. p.Z -= (s.Z - 1) / 2;
  208. //// Create VManip for affected area, emerge our area, modify area
  209. //// inside VManip, then blit back.
  210. v3s16 bp1 = getNodeBlockPos(p);
  211. v3s16 bp2 = getNodeBlockPos(p + s - v3s16(1, 1, 1));
  212. MMVManip vm(map);
  213. vm.initialEmerge(bp1, bp2);
  214. blitToVManip(&vm, p, rot, force_place);
  215. voxalgo::blit_back_with_light(map, &vm, &modified_blocks);
  216. //// Carry out post-map-modification actions
  217. //// Create & dispatch map modification events to observers
  218. MapEditEvent event;
  219. event.type = MEET_OTHER;
  220. event.setModifiedBlocks(modified_blocks);
  221. map->dispatchEvent(event);
  222. }
  223. bool Schematic::deserializeFromMts(std::istream *is)
  224. {
  225. std::istream &ss = *is;
  226. content_t cignore = CONTENT_IGNORE;
  227. bool have_cignore = false;
  228. //// Read signature
  229. u32 signature = readU32(ss);
  230. if (signature != MTSCHEM_FILE_SIGNATURE) {
  231. errorstream << __FUNCTION__ << ": invalid schematic "
  232. "file" << std::endl;
  233. return false;
  234. }
  235. //// Read version
  236. u16 version = readU16(ss);
  237. if (version > MTSCHEM_FILE_VER_HIGHEST_READ) {
  238. errorstream << __FUNCTION__ << ": unsupported schematic "
  239. "file version" << std::endl;
  240. return false;
  241. }
  242. //// Read size
  243. size = readV3S16(ss);
  244. //// Read Y-slice probability values
  245. delete []slice_probs;
  246. slice_probs = new u8[size.Y];
  247. for (int y = 0; y != size.Y; y++)
  248. slice_probs[y] = (version >= 3) ? readU8(ss) : MTSCHEM_PROB_ALWAYS_OLD;
  249. //// Read node names
  250. NodeResolver::reset();
  251. u16 nidmapcount = readU16(ss);
  252. for (int i = 0; i != nidmapcount; i++) {
  253. std::string name = deSerializeString16(ss);
  254. // Instances of "ignore" from v1 are converted to air (and instances
  255. // are fixed to have MTSCHEM_PROB_NEVER later on).
  256. if (name == "ignore") {
  257. name = "air";
  258. cignore = i;
  259. have_cignore = true;
  260. }
  261. m_nodenames.push_back(name);
  262. }
  263. // Prepare for node resolver
  264. m_nnlistsizes.push_back(m_nodenames.size());
  265. //// Read node data
  266. size_t nodecount = size.X * size.Y * size.Z;
  267. delete []schemdata;
  268. schemdata = new MapNode[nodecount];
  269. std::stringstream d_ss(std::ios_base::binary | std::ios_base::in | std::ios_base::out);
  270. decompress(ss, d_ss, MTSCHEM_MAPNODE_SER_FMT_VER);
  271. MapNode::deSerializeBulk(d_ss, MTSCHEM_MAPNODE_SER_FMT_VER, schemdata,
  272. nodecount, 2, 2);
  273. // Fix probability values for nodes that were ignore; removed in v2
  274. if (version < 2) {
  275. for (size_t i = 0; i != nodecount; i++) {
  276. if (schemdata[i].param1 == 0)
  277. schemdata[i].param1 = MTSCHEM_PROB_ALWAYS_OLD;
  278. if (have_cignore && schemdata[i].getContent() == cignore)
  279. schemdata[i].param1 = MTSCHEM_PROB_NEVER;
  280. }
  281. }
  282. // Fix probability values for probability range truncation introduced in v4
  283. if (version < 4) {
  284. for (s16 y = 0; y != size.Y; y++)
  285. slice_probs[y] >>= 1;
  286. for (size_t i = 0; i != nodecount; i++)
  287. schemdata[i].param1 >>= 1;
  288. }
  289. return true;
  290. }
  291. bool Schematic::serializeToMts(std::ostream *os) const
  292. {
  293. // Nodes must not be resolved (-> condensed)
  294. // checking here is not possible because "schemdata" might be temporary.
  295. std::ostream &ss = *os;
  296. writeU32(ss, MTSCHEM_FILE_SIGNATURE); // signature
  297. writeU16(ss, MTSCHEM_FILE_VER_HIGHEST_WRITE); // version
  298. writeV3S16(ss, size); // schematic size
  299. for (int y = 0; y != size.Y; y++) // Y slice probabilities
  300. writeU8(ss, slice_probs[y]);
  301. writeU16(ss, m_nodenames.size()); // name count
  302. for (size_t i = 0; i != m_nodenames.size(); i++) {
  303. ss << serializeString16(m_nodenames[i]); // node names
  304. }
  305. // compressed bulk node data
  306. auto buf = MapNode::serializeBulk(MTSCHEM_MAPNODE_SER_FMT_VER,
  307. schemdata, size.X * size.Y * size.Z, 2, 2);
  308. compress(buf, ss, MTSCHEM_MAPNODE_SER_FMT_VER);
  309. return true;
  310. }
  311. bool Schematic::serializeToLua(std::ostream *os, bool use_comments,
  312. u32 indent_spaces) const
  313. {
  314. std::ostream &ss = *os;
  315. std::string indent("\t");
  316. if (indent_spaces > 0)
  317. indent.assign(indent_spaces, ' ');
  318. bool resolve_done = isResolveDone();
  319. FATAL_ERROR_IF(resolve_done && !m_ndef, "serializeToLua: NodeDefManager is required");
  320. //// Write header
  321. {
  322. ss << "schematic = {" << std::endl;
  323. ss << indent << "size = "
  324. << "{x=" << size.X
  325. << ", y=" << size.Y
  326. << ", z=" << size.Z
  327. << "}," << std::endl;
  328. }
  329. //// Write y-slice probabilities
  330. {
  331. ss << indent << "yslice_prob = {" << std::endl;
  332. for (u16 y = 0; y != size.Y; y++) {
  333. u8 probability = slice_probs[y] & MTSCHEM_PROB_MASK;
  334. ss << indent << indent << "{"
  335. << "ypos=" << y
  336. << ", prob=" << (u16)probability * 2
  337. << "}," << std::endl;
  338. }
  339. ss << indent << "}," << std::endl;
  340. }
  341. //// Write node data
  342. {
  343. ss << indent << "data = {" << std::endl;
  344. u32 i = 0;
  345. for (u16 z = 0; z != size.Z; z++)
  346. for (u16 y = 0; y != size.Y; y++) {
  347. if (use_comments) {
  348. ss << std::endl
  349. << indent << indent
  350. << "-- z=" << z
  351. << ", y=" << y << std::endl;
  352. }
  353. for (u16 x = 0; x != size.X; x++, i++) {
  354. u8 probability = schemdata[i].param1 & MTSCHEM_PROB_MASK;
  355. bool force_place = schemdata[i].param1 & MTSCHEM_FORCE_PLACE;
  356. // After node resolving: real content_t, lookup using NodeDefManager
  357. // Prior node resolving: condensed ID, lookup using m_nodenames
  358. content_t c = schemdata[i].getContent();
  359. ss << indent << indent << "{" << "name=\"";
  360. if (!resolve_done) {
  361. // Prior node resolving (eg. direct schematic load)
  362. FATAL_ERROR_IF(c >= m_nodenames.size(), "Invalid node list");
  363. ss << m_nodenames[c];
  364. } else {
  365. // After node resolving (eg. biome decoration)
  366. ss << m_ndef->get(c).name;
  367. }
  368. ss << "\", prob=" << (u16)probability * 2
  369. << ", param2=" << (u16)schemdata[i].param2;
  370. if (force_place)
  371. ss << ", force_place=true";
  372. ss << "}," << std::endl;
  373. }
  374. }
  375. ss << indent << "}," << std::endl;
  376. }
  377. ss << "}" << std::endl;
  378. return true;
  379. }
  380. bool Schematic::loadSchematicFromFile(const std::string &filename,
  381. const NodeDefManager *ndef, StringMap *replace_names)
  382. {
  383. std::ifstream is(filename.c_str(), std::ios_base::binary);
  384. if (!is.good()) {
  385. errorstream << __FUNCTION__ << ": unable to open file '"
  386. << filename << "'" << std::endl;
  387. return false;
  388. }
  389. if (!m_ndef)
  390. m_ndef = ndef;
  391. if (!deserializeFromMts(&is))
  392. return false;
  393. name = filename;
  394. if (replace_names) {
  395. for (std::string &node_name : m_nodenames) {
  396. StringMap::iterator it = replace_names->find(node_name);
  397. if (it != replace_names->end())
  398. node_name = it->second;
  399. }
  400. }
  401. if (m_ndef)
  402. m_ndef->pendNodeResolve(this);
  403. return true;
  404. }
  405. bool Schematic::saveSchematicToFile(const std::string &filename,
  406. const NodeDefManager *ndef)
  407. {
  408. Schematic *schem = this;
  409. bool needs_condense = isResolveDone();
  410. if (!m_ndef)
  411. m_ndef = ndef;
  412. if (needs_condense) {
  413. if (!m_ndef)
  414. return false;
  415. schem = (Schematic *)this->clone();
  416. schem->condenseContentIds();
  417. }
  418. std::ostringstream os(std::ios_base::binary);
  419. bool status = schem->serializeToMts(&os);
  420. if (needs_condense)
  421. delete schem;
  422. if (!status)
  423. return false;
  424. return fs::safeWriteToFile(filename, os.str());
  425. }
  426. bool Schematic::getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2)
  427. {
  428. MMVManip *vm = new MMVManip(map);
  429. v3s16 bp1 = getNodeBlockPos(p1);
  430. v3s16 bp2 = getNodeBlockPos(p2);
  431. vm->initialEmerge(bp1, bp2);
  432. size = p2 - p1 + 1;
  433. slice_probs = new u8[size.Y];
  434. for (s16 y = 0; y != size.Y; y++)
  435. slice_probs[y] = MTSCHEM_PROB_ALWAYS;
  436. schemdata = new MapNode[size.X * size.Y * size.Z];
  437. u32 i = 0;
  438. for (s16 z = p1.Z; z <= p2.Z; z++)
  439. for (s16 y = p1.Y; y <= p2.Y; y++) {
  440. u32 vi = vm->m_area.index(p1.X, y, z);
  441. for (s16 x = p1.X; x <= p2.X; x++, i++, vi++) {
  442. schemdata[i] = vm->m_data[vi];
  443. schemdata[i].param1 = MTSCHEM_PROB_ALWAYS;
  444. }
  445. }
  446. delete vm;
  447. // Reset and mark as complete
  448. NodeResolver::reset(true);
  449. return true;
  450. }
  451. void Schematic::applyProbabilities(v3s16 p0,
  452. std::vector<std::pair<v3s16, u8> > *plist,
  453. std::vector<std::pair<s16, u8> > *splist)
  454. {
  455. for (size_t i = 0; i != plist->size(); i++) {
  456. v3s16 p = (*plist)[i].first - p0;
  457. int index = p.Z * (size.Y * size.X) + p.Y * size.X + p.X;
  458. if (index < size.Z * size.Y * size.X) {
  459. u8 prob = (*plist)[i].second;
  460. schemdata[index].param1 = prob;
  461. // trim unnecessary node names from schematic
  462. if (prob == MTSCHEM_PROB_NEVER)
  463. schemdata[index].setContent(CONTENT_AIR);
  464. }
  465. }
  466. for (size_t i = 0; i != splist->size(); i++) {
  467. s16 slice = (*splist)[i].first;
  468. if (slice < size.Y)
  469. slice_probs[slice] = (*splist)[i].second;
  470. }
  471. }
  472. void Schematic::condenseContentIds()
  473. {
  474. std::unordered_map<content_t, content_t> nodeidmap;
  475. content_t numids = 0;
  476. // Reset node resolve fields
  477. NodeResolver::reset();
  478. size_t nodecount = size.X * size.Y * size.Z;
  479. for (size_t i = 0; i != nodecount; i++) {
  480. content_t id;
  481. content_t c = schemdata[i].getContent();
  482. auto it = nodeidmap.find(c);
  483. if (it == nodeidmap.end()) {
  484. id = numids;
  485. numids++;
  486. m_nodenames.push_back(m_ndef->get(c).name);
  487. nodeidmap.emplace(c, id);
  488. } else {
  489. id = it->second;
  490. }
  491. schemdata[i].setContent(id);
  492. }
  493. }