mg_schematic.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  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 *> lighting_modified_blocks;
  192. std::map<v3s16, MapBlock *> modified_blocks;
  193. std::map<v3s16, MapBlock *>::iterator it;
  194. assert(map != NULL);
  195. assert(schemdata != NULL);
  196. sanity_check(m_ndef != NULL);
  197. //// Determine effective rotation and effective schematic dimensions
  198. if (rot == ROTATE_RAND)
  199. rot = (Rotation)myrand_range(ROTATE_0, ROTATE_270);
  200. v3s16 s = (rot == ROTATE_90 || rot == ROTATE_270) ?
  201. v3s16(size.Z, size.Y, size.X) : size;
  202. //// Adjust placement position if necessary
  203. if (flags & DECO_PLACE_CENTER_X)
  204. p.X -= (s.X - 1) / 2;
  205. if (flags & DECO_PLACE_CENTER_Y)
  206. p.Y -= (s.Y - 1) / 2;
  207. if (flags & DECO_PLACE_CENTER_Z)
  208. p.Z -= (s.Z - 1) / 2;
  209. //// Create VManip for effected area, emerge our area, modify area
  210. //// inside VManip, then blit back.
  211. v3s16 bp1 = getNodeBlockPos(p);
  212. v3s16 bp2 = getNodeBlockPos(p + s - v3s16(1, 1, 1));
  213. MMVManip vm(map);
  214. vm.initialEmerge(bp1, bp2);
  215. blitToVManip(&vm, p, rot, force_place);
  216. voxalgo::blit_back_with_light(map, &vm, &modified_blocks);
  217. //// Carry out post-map-modification actions
  218. //// Create & dispatch map modification events to observers
  219. MapEditEvent event;
  220. event.type = MEET_OTHER;
  221. for (it = modified_blocks.begin(); it != modified_blocks.end(); ++it)
  222. event.modified_blocks.insert(it->first);
  223. map->dispatchEvent(event);
  224. }
  225. bool Schematic::deserializeFromMts(std::istream *is)
  226. {
  227. std::istream &ss = *is;
  228. content_t cignore = CONTENT_IGNORE;
  229. bool have_cignore = false;
  230. //// Read signature
  231. u32 signature = readU32(ss);
  232. if (signature != MTSCHEM_FILE_SIGNATURE) {
  233. errorstream << __FUNCTION__ << ": invalid schematic "
  234. "file" << std::endl;
  235. return false;
  236. }
  237. //// Read version
  238. u16 version = readU16(ss);
  239. if (version > MTSCHEM_FILE_VER_HIGHEST_READ) {
  240. errorstream << __FUNCTION__ << ": unsupported schematic "
  241. "file version" << std::endl;
  242. return false;
  243. }
  244. //// Read size
  245. size = readV3S16(ss);
  246. //// Read Y-slice probability values
  247. delete []slice_probs;
  248. slice_probs = new u8[size.Y];
  249. for (int y = 0; y != size.Y; y++)
  250. slice_probs[y] = (version >= 3) ? readU8(ss) : MTSCHEM_PROB_ALWAYS_OLD;
  251. //// Read node names
  252. NodeResolver::reset();
  253. u16 nidmapcount = readU16(ss);
  254. for (int i = 0; i != nidmapcount; i++) {
  255. std::string name = deSerializeString16(ss);
  256. // Instances of "ignore" from v1 are converted to air (and instances
  257. // are fixed to have MTSCHEM_PROB_NEVER later on).
  258. if (name == "ignore") {
  259. name = "air";
  260. cignore = i;
  261. have_cignore = true;
  262. }
  263. m_nodenames.push_back(name);
  264. }
  265. // Prepare for node resolver
  266. m_nnlistsizes.push_back(m_nodenames.size());
  267. //// Read node data
  268. size_t nodecount = size.X * size.Y * size.Z;
  269. delete []schemdata;
  270. schemdata = new MapNode[nodecount];
  271. std::stringstream d_ss(std::ios_base::binary | std::ios_base::in | std::ios_base::out);
  272. decompress(ss, d_ss, MTSCHEM_MAPNODE_SER_FMT_VER);
  273. MapNode::deSerializeBulk(d_ss, MTSCHEM_MAPNODE_SER_FMT_VER, schemdata,
  274. nodecount, 2, 2);
  275. // Fix probability values for nodes that were ignore; removed in v2
  276. if (version < 2) {
  277. for (size_t i = 0; i != nodecount; i++) {
  278. if (schemdata[i].param1 == 0)
  279. schemdata[i].param1 = MTSCHEM_PROB_ALWAYS_OLD;
  280. if (have_cignore && schemdata[i].getContent() == cignore)
  281. schemdata[i].param1 = MTSCHEM_PROB_NEVER;
  282. }
  283. }
  284. // Fix probability values for probability range truncation introduced in v4
  285. if (version < 4) {
  286. for (s16 y = 0; y != size.Y; y++)
  287. slice_probs[y] >>= 1;
  288. for (size_t i = 0; i != nodecount; i++)
  289. schemdata[i].param1 >>= 1;
  290. }
  291. return true;
  292. }
  293. bool Schematic::serializeToMts(std::ostream *os) const
  294. {
  295. // Nodes must not be resolved (-> condensed)
  296. // checking here is not possible because "schemdata" might be temporary.
  297. std::ostream &ss = *os;
  298. writeU32(ss, MTSCHEM_FILE_SIGNATURE); // signature
  299. writeU16(ss, MTSCHEM_FILE_VER_HIGHEST_WRITE); // version
  300. writeV3S16(ss, size); // schematic size
  301. for (int y = 0; y != size.Y; y++) // Y slice probabilities
  302. writeU8(ss, slice_probs[y]);
  303. writeU16(ss, m_nodenames.size()); // name count
  304. for (size_t i = 0; i != m_nodenames.size(); i++) {
  305. ss << serializeString16(m_nodenames[i]); // node names
  306. }
  307. // compressed bulk node data
  308. SharedBuffer<u8> buf = MapNode::serializeBulk(MTSCHEM_MAPNODE_SER_FMT_VER,
  309. schemdata, size.X * size.Y * size.Z, 2, 2);
  310. compress(buf, ss, MTSCHEM_MAPNODE_SER_FMT_VER);
  311. return true;
  312. }
  313. bool Schematic::serializeToLua(std::ostream *os, bool use_comments,
  314. u32 indent_spaces) const
  315. {
  316. std::ostream &ss = *os;
  317. std::string indent("\t");
  318. if (indent_spaces > 0)
  319. indent.assign(indent_spaces, ' ');
  320. bool resolve_done = isResolveDone();
  321. FATAL_ERROR_IF(resolve_done && !m_ndef, "serializeToLua: NodeDefManager is required");
  322. //// Write header
  323. {
  324. ss << "schematic = {" << std::endl;
  325. ss << indent << "size = "
  326. << "{x=" << size.X
  327. << ", y=" << size.Y
  328. << ", z=" << size.Z
  329. << "}," << std::endl;
  330. }
  331. //// Write y-slice probabilities
  332. {
  333. ss << indent << "yslice_prob = {" << std::endl;
  334. for (u16 y = 0; y != size.Y; y++) {
  335. u8 probability = slice_probs[y] & MTSCHEM_PROB_MASK;
  336. ss << indent << indent << "{"
  337. << "ypos=" << y
  338. << ", prob=" << (u16)probability * 2
  339. << "}," << std::endl;
  340. }
  341. ss << indent << "}," << std::endl;
  342. }
  343. //// Write node data
  344. {
  345. ss << indent << "data = {" << std::endl;
  346. u32 i = 0;
  347. for (u16 z = 0; z != size.Z; z++)
  348. for (u16 y = 0; y != size.Y; y++) {
  349. if (use_comments) {
  350. ss << std::endl
  351. << indent << indent
  352. << "-- z=" << z
  353. << ", y=" << y << std::endl;
  354. }
  355. for (u16 x = 0; x != size.X; x++, i++) {
  356. u8 probability = schemdata[i].param1 & MTSCHEM_PROB_MASK;
  357. bool force_place = schemdata[i].param1 & MTSCHEM_FORCE_PLACE;
  358. // After node resolving: real content_t, lookup using NodeDefManager
  359. // Prior node resolving: condensed ID, lookup using m_nodenames
  360. content_t c = schemdata[i].getContent();
  361. ss << indent << indent << "{" << "name=\"";
  362. if (!resolve_done) {
  363. // Prior node resolving (eg. direct schematic load)
  364. FATAL_ERROR_IF(c >= m_nodenames.size(), "Invalid node list");
  365. ss << m_nodenames[c];
  366. } else {
  367. // After node resolving (eg. biome decoration)
  368. ss << m_ndef->get(c).name;
  369. }
  370. ss << "\", prob=" << (u16)probability * 2
  371. << ", param2=" << (u16)schemdata[i].param2;
  372. if (force_place)
  373. ss << ", force_place=true";
  374. ss << "}," << std::endl;
  375. }
  376. }
  377. ss << indent << "}," << std::endl;
  378. }
  379. ss << "}" << std::endl;
  380. return true;
  381. }
  382. bool Schematic::loadSchematicFromFile(const std::string &filename,
  383. const NodeDefManager *ndef, StringMap *replace_names)
  384. {
  385. std::ifstream is(filename.c_str(), std::ios_base::binary);
  386. if (!is.good()) {
  387. errorstream << __FUNCTION__ << ": unable to open file '"
  388. << filename << "'" << std::endl;
  389. return false;
  390. }
  391. if (!m_ndef)
  392. m_ndef = ndef;
  393. if (!deserializeFromMts(&is))
  394. return false;
  395. name = filename;
  396. if (replace_names) {
  397. for (std::string &node_name : m_nodenames) {
  398. StringMap::iterator it = replace_names->find(node_name);
  399. if (it != replace_names->end())
  400. node_name = it->second;
  401. }
  402. }
  403. if (m_ndef)
  404. m_ndef->pendNodeResolve(this);
  405. return true;
  406. }
  407. bool Schematic::saveSchematicToFile(const std::string &filename,
  408. const NodeDefManager *ndef)
  409. {
  410. Schematic *schem = this;
  411. bool needs_condense = isResolveDone();
  412. if (!m_ndef)
  413. m_ndef = ndef;
  414. if (needs_condense) {
  415. if (!m_ndef)
  416. return false;
  417. schem = (Schematic *)this->clone();
  418. schem->condenseContentIds();
  419. }
  420. std::ostringstream os(std::ios_base::binary);
  421. bool status = schem->serializeToMts(&os);
  422. if (needs_condense)
  423. delete schem;
  424. if (!status)
  425. return false;
  426. return fs::safeWriteToFile(filename, os.str());
  427. }
  428. bool Schematic::getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2)
  429. {
  430. MMVManip *vm = new MMVManip(map);
  431. v3s16 bp1 = getNodeBlockPos(p1);
  432. v3s16 bp2 = getNodeBlockPos(p2);
  433. vm->initialEmerge(bp1, bp2);
  434. size = p2 - p1 + 1;
  435. slice_probs = new u8[size.Y];
  436. for (s16 y = 0; y != size.Y; y++)
  437. slice_probs[y] = MTSCHEM_PROB_ALWAYS;
  438. schemdata = new MapNode[size.X * size.Y * size.Z];
  439. u32 i = 0;
  440. for (s16 z = p1.Z; z <= p2.Z; z++)
  441. for (s16 y = p1.Y; y <= p2.Y; y++) {
  442. u32 vi = vm->m_area.index(p1.X, y, z);
  443. for (s16 x = p1.X; x <= p2.X; x++, i++, vi++) {
  444. schemdata[i] = vm->m_data[vi];
  445. schemdata[i].param1 = MTSCHEM_PROB_ALWAYS;
  446. }
  447. }
  448. delete vm;
  449. // Reset and mark as complete
  450. NodeResolver::reset(true);
  451. return true;
  452. }
  453. void Schematic::applyProbabilities(v3s16 p0,
  454. std::vector<std::pair<v3s16, u8> > *plist,
  455. std::vector<std::pair<s16, u8> > *splist)
  456. {
  457. for (size_t i = 0; i != plist->size(); i++) {
  458. v3s16 p = (*plist)[i].first - p0;
  459. int index = p.Z * (size.Y * size.X) + p.Y * size.X + p.X;
  460. if (index < size.Z * size.Y * size.X) {
  461. u8 prob = (*plist)[i].second;
  462. schemdata[index].param1 = prob;
  463. // trim unnecessary node names from schematic
  464. if (prob == MTSCHEM_PROB_NEVER)
  465. schemdata[index].setContent(CONTENT_AIR);
  466. }
  467. }
  468. for (size_t i = 0; i != splist->size(); i++) {
  469. s16 slice = (*splist)[i].first;
  470. if (slice < size.Y)
  471. slice_probs[slice] = (*splist)[i].second;
  472. }
  473. }
  474. void Schematic::condenseContentIds()
  475. {
  476. std::unordered_map<content_t, content_t> nodeidmap;
  477. content_t numids = 0;
  478. // Reset node resolve fields
  479. NodeResolver::reset();
  480. size_t nodecount = size.X * size.Y * size.Z;
  481. for (size_t i = 0; i != nodecount; i++) {
  482. content_t id;
  483. content_t c = schemdata[i].getContent();
  484. auto it = nodeidmap.find(c);
  485. if (it == nodeidmap.end()) {
  486. id = numids;
  487. numids++;
  488. m_nodenames.push_back(m_ndef->get(c).name);
  489. nodeidmap.emplace(std::make_pair(c, id));
  490. } else {
  491. id = it->second;
  492. }
  493. schemdata[i].setContent(id);
  494. }
  495. }