mg_schematic.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  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. void SchematicManager::clear()
  38. {
  39. EmergeManager *emerge = m_server->getEmergeManager();
  40. // Remove all dangling references in Decorations
  41. DecorationManager *decomgr = emerge->decomgr;
  42. for (size_t i = 0; i != decomgr->getNumObjects(); i++) {
  43. Decoration *deco = (Decoration *)decomgr->getRaw(i);
  44. try {
  45. DecoSchematic *dschem = dynamic_cast<DecoSchematic *>(deco);
  46. if (dschem)
  47. dschem->schematic = NULL;
  48. } catch (const std::bad_cast &) {
  49. }
  50. }
  51. ObjDefManager::clear();
  52. }
  53. ///////////////////////////////////////////////////////////////////////////////
  54. Schematic::Schematic()
  55. = default;
  56. Schematic::~Schematic()
  57. {
  58. delete []schemdata;
  59. delete []slice_probs;
  60. }
  61. void Schematic::resolveNodeNames()
  62. {
  63. getIdsFromNrBacklog(&c_nodes, true, CONTENT_AIR);
  64. size_t bufsize = size.X * size.Y * size.Z;
  65. for (size_t i = 0; i != bufsize; i++) {
  66. content_t c_original = schemdata[i].getContent();
  67. content_t c_new = c_nodes[c_original];
  68. schemdata[i].setContent(c_new);
  69. }
  70. }
  71. void Schematic::blitToVManip(MMVManip *vm, v3s16 p, Rotation rot, bool force_place)
  72. {
  73. sanity_check(m_ndef != NULL);
  74. int xstride = 1;
  75. int ystride = size.X;
  76. int zstride = size.X * size.Y;
  77. s16 sx = size.X;
  78. s16 sy = size.Y;
  79. s16 sz = size.Z;
  80. int i_start, i_step_x, i_step_z;
  81. switch (rot) {
  82. case ROTATE_90:
  83. i_start = sx - 1;
  84. i_step_x = zstride;
  85. i_step_z = -xstride;
  86. SWAP(s16, sx, sz);
  87. break;
  88. case ROTATE_180:
  89. i_start = zstride * (sz - 1) + sx - 1;
  90. i_step_x = -xstride;
  91. i_step_z = -zstride;
  92. break;
  93. case ROTATE_270:
  94. i_start = zstride * (sz - 1);
  95. i_step_x = -zstride;
  96. i_step_z = xstride;
  97. SWAP(s16, sx, sz);
  98. break;
  99. default:
  100. i_start = 0;
  101. i_step_x = xstride;
  102. i_step_z = zstride;
  103. }
  104. s16 y_map = p.Y;
  105. for (s16 y = 0; y != sy; y++) {
  106. if ((slice_probs[y] != MTSCHEM_PROB_ALWAYS) &&
  107. (slice_probs[y] <= myrand_range(1, MTSCHEM_PROB_ALWAYS)))
  108. continue;
  109. for (s16 z = 0; z != sz; z++) {
  110. u32 i = z * i_step_z + y * ystride + i_start;
  111. for (s16 x = 0; x != sx; x++, i += i_step_x) {
  112. u32 vi = vm->m_area.index(p.X + x, y_map, p.Z + z);
  113. if (!vm->m_area.contains(vi))
  114. continue;
  115. if (schemdata[i].getContent() == CONTENT_IGNORE)
  116. continue;
  117. u8 placement_prob = schemdata[i].param1 & MTSCHEM_PROB_MASK;
  118. bool force_place_node = schemdata[i].param1 & MTSCHEM_FORCE_PLACE;
  119. if (placement_prob == MTSCHEM_PROB_NEVER)
  120. continue;
  121. if (!force_place && !force_place_node) {
  122. content_t c = vm->m_data[vi].getContent();
  123. if (c != CONTENT_AIR && c != CONTENT_IGNORE)
  124. continue;
  125. }
  126. if ((placement_prob != MTSCHEM_PROB_ALWAYS) &&
  127. (placement_prob <= myrand_range(1, MTSCHEM_PROB_ALWAYS)))
  128. continue;
  129. vm->m_data[vi] = schemdata[i];
  130. vm->m_data[vi].param1 = 0;
  131. if (rot)
  132. vm->m_data[vi].rotateAlongYAxis(m_ndef, rot);
  133. }
  134. }
  135. y_map++;
  136. }
  137. }
  138. bool Schematic::placeOnVManip(MMVManip *vm, v3s16 p, u32 flags,
  139. Rotation rot, bool force_place)
  140. {
  141. assert(vm != NULL);
  142. assert(schemdata != NULL);
  143. sanity_check(m_ndef != NULL);
  144. //// Determine effective rotation and effective schematic dimensions
  145. if (rot == ROTATE_RAND)
  146. rot = (Rotation)myrand_range(ROTATE_0, ROTATE_270);
  147. v3s16 s = (rot == ROTATE_90 || rot == ROTATE_270) ?
  148. v3s16(size.Z, size.Y, size.X) : size;
  149. //// Adjust placement position if necessary
  150. if (flags & DECO_PLACE_CENTER_X)
  151. p.X -= (s.X - 1) / 2;
  152. if (flags & DECO_PLACE_CENTER_Y)
  153. p.Y -= (s.Y - 1) / 2;
  154. if (flags & DECO_PLACE_CENTER_Z)
  155. p.Z -= (s.Z - 1) / 2;
  156. blitToVManip(vm, p, rot, force_place);
  157. return vm->m_area.contains(VoxelArea(p, p + s - v3s16(1, 1, 1)));
  158. }
  159. void Schematic::placeOnMap(ServerMap *map, v3s16 p, u32 flags,
  160. Rotation rot, bool force_place)
  161. {
  162. std::map<v3s16, MapBlock *> lighting_modified_blocks;
  163. std::map<v3s16, MapBlock *> modified_blocks;
  164. std::map<v3s16, MapBlock *>::iterator it;
  165. assert(map != NULL);
  166. assert(schemdata != NULL);
  167. sanity_check(m_ndef != NULL);
  168. //// Determine effective rotation and effective schematic dimensions
  169. if (rot == ROTATE_RAND)
  170. rot = (Rotation)myrand_range(ROTATE_0, ROTATE_270);
  171. v3s16 s = (rot == ROTATE_90 || rot == ROTATE_270) ?
  172. v3s16(size.Z, size.Y, size.X) : size;
  173. //// Adjust placement position if necessary
  174. if (flags & DECO_PLACE_CENTER_X)
  175. p.X -= (s.X - 1) / 2;
  176. if (flags & DECO_PLACE_CENTER_Y)
  177. p.Y -= (s.Y - 1) / 2;
  178. if (flags & DECO_PLACE_CENTER_Z)
  179. p.Z -= (s.Z - 1) / 2;
  180. //// Create VManip for effected area, emerge our area, modify area
  181. //// inside VManip, then blit back.
  182. v3s16 bp1 = getNodeBlockPos(p);
  183. v3s16 bp2 = getNodeBlockPos(p + s - v3s16(1, 1, 1));
  184. MMVManip vm(map);
  185. vm.initialEmerge(bp1, bp2);
  186. blitToVManip(&vm, p, rot, force_place);
  187. voxalgo::blit_back_with_light(map, &vm, &modified_blocks);
  188. //// Carry out post-map-modification actions
  189. //// Create & dispatch map modification events to observers
  190. MapEditEvent event;
  191. event.type = MEET_OTHER;
  192. for (it = modified_blocks.begin(); it != modified_blocks.end(); ++it)
  193. event.modified_blocks.insert(it->first);
  194. map->dispatchEvent(&event);
  195. }
  196. bool Schematic::deserializeFromMts(std::istream *is,
  197. std::vector<std::string> *names)
  198. {
  199. std::istream &ss = *is;
  200. content_t cignore = CONTENT_IGNORE;
  201. bool have_cignore = false;
  202. //// Read signature
  203. u32 signature = readU32(ss);
  204. if (signature != MTSCHEM_FILE_SIGNATURE) {
  205. errorstream << __FUNCTION__ << ": invalid schematic "
  206. "file" << std::endl;
  207. return false;
  208. }
  209. //// Read version
  210. u16 version = readU16(ss);
  211. if (version > MTSCHEM_FILE_VER_HIGHEST_READ) {
  212. errorstream << __FUNCTION__ << ": unsupported schematic "
  213. "file version" << std::endl;
  214. return false;
  215. }
  216. //// Read size
  217. size = readV3S16(ss);
  218. //// Read Y-slice probability values
  219. delete []slice_probs;
  220. slice_probs = new u8[size.Y];
  221. for (int y = 0; y != size.Y; y++)
  222. slice_probs[y] = (version >= 3) ? readU8(ss) : MTSCHEM_PROB_ALWAYS_OLD;
  223. //// Read node names
  224. u16 nidmapcount = readU16(ss);
  225. for (int i = 0; i != nidmapcount; i++) {
  226. std::string name = deSerializeString(ss);
  227. // Instances of "ignore" from v1 are converted to air (and instances
  228. // are fixed to have MTSCHEM_PROB_NEVER later on).
  229. if (name == "ignore") {
  230. name = "air";
  231. cignore = i;
  232. have_cignore = true;
  233. }
  234. names->push_back(name);
  235. }
  236. //// Read node data
  237. size_t nodecount = size.X * size.Y * size.Z;
  238. delete []schemdata;
  239. schemdata = new MapNode[nodecount];
  240. MapNode::deSerializeBulk(ss, SER_FMT_VER_HIGHEST_READ, schemdata,
  241. nodecount, 2, 2, true);
  242. // Fix probability values for nodes that were ignore; removed in v2
  243. if (version < 2) {
  244. for (size_t i = 0; i != nodecount; i++) {
  245. if (schemdata[i].param1 == 0)
  246. schemdata[i].param1 = MTSCHEM_PROB_ALWAYS_OLD;
  247. if (have_cignore && schemdata[i].getContent() == cignore)
  248. schemdata[i].param1 = MTSCHEM_PROB_NEVER;
  249. }
  250. }
  251. // Fix probability values for probability range truncation introduced in v4
  252. if (version < 4) {
  253. for (s16 y = 0; y != size.Y; y++)
  254. slice_probs[y] >>= 1;
  255. for (size_t i = 0; i != nodecount; i++)
  256. schemdata[i].param1 >>= 1;
  257. }
  258. return true;
  259. }
  260. bool Schematic::serializeToMts(std::ostream *os,
  261. const std::vector<std::string> &names)
  262. {
  263. std::ostream &ss = *os;
  264. writeU32(ss, MTSCHEM_FILE_SIGNATURE); // signature
  265. writeU16(ss, MTSCHEM_FILE_VER_HIGHEST_WRITE); // version
  266. writeV3S16(ss, size); // schematic size
  267. for (int y = 0; y != size.Y; y++) // Y slice probabilities
  268. writeU8(ss, slice_probs[y]);
  269. writeU16(ss, names.size()); // name count
  270. for (size_t i = 0; i != names.size(); i++)
  271. ss << serializeString(names[i]); // node names
  272. // compressed bulk node data
  273. MapNode::serializeBulk(ss, SER_FMT_VER_HIGHEST_WRITE,
  274. schemdata, size.X * size.Y * size.Z, 2, 2, true);
  275. return true;
  276. }
  277. bool Schematic::serializeToLua(std::ostream *os,
  278. const std::vector<std::string> &names, bool use_comments, u32 indent_spaces)
  279. {
  280. std::ostream &ss = *os;
  281. std::string indent("\t");
  282. if (indent_spaces > 0)
  283. indent.assign(indent_spaces, ' ');
  284. //// Write header
  285. {
  286. ss << "schematic = {" << std::endl;
  287. ss << indent << "size = "
  288. << "{x=" << size.X
  289. << ", y=" << size.Y
  290. << ", z=" << size.Z
  291. << "}," << std::endl;
  292. }
  293. //// Write y-slice probabilities
  294. {
  295. ss << indent << "yslice_prob = {" << std::endl;
  296. for (u16 y = 0; y != size.Y; y++) {
  297. u8 probability = slice_probs[y] & MTSCHEM_PROB_MASK;
  298. ss << indent << indent << "{"
  299. << "ypos=" << y
  300. << ", prob=" << (u16)probability * 2
  301. << "}," << std::endl;
  302. }
  303. ss << indent << "}," << std::endl;
  304. }
  305. //// Write node data
  306. {
  307. ss << indent << "data = {" << std::endl;
  308. u32 i = 0;
  309. for (u16 z = 0; z != size.Z; z++)
  310. for (u16 y = 0; y != size.Y; y++) {
  311. if (use_comments) {
  312. ss << std::endl
  313. << indent << indent
  314. << "-- z=" << z
  315. << ", y=" << y << std::endl;
  316. }
  317. for (u16 x = 0; x != size.X; x++, i++) {
  318. u8 probability = schemdata[i].param1 & MTSCHEM_PROB_MASK;
  319. bool force_place = schemdata[i].param1 & MTSCHEM_FORCE_PLACE;
  320. ss << indent << indent << "{"
  321. << "name=\"" << names[schemdata[i].getContent()]
  322. << "\", prob=" << (u16)probability * 2
  323. << ", param2=" << (u16)schemdata[i].param2;
  324. if (force_place)
  325. ss << ", force_place=true";
  326. ss << "}," << std::endl;
  327. }
  328. }
  329. ss << indent << "}," << std::endl;
  330. }
  331. ss << "}" << std::endl;
  332. return true;
  333. }
  334. bool Schematic::loadSchematicFromFile(const std::string &filename,
  335. const NodeDefManager *ndef, StringMap *replace_names)
  336. {
  337. std::ifstream is(filename.c_str(), std::ios_base::binary);
  338. if (!is.good()) {
  339. errorstream << __FUNCTION__ << ": unable to open file '"
  340. << filename << "'" << std::endl;
  341. return false;
  342. }
  343. size_t origsize = m_nodenames.size();
  344. if (!deserializeFromMts(&is, &m_nodenames))
  345. return false;
  346. m_nnlistsizes.push_back(m_nodenames.size() - origsize);
  347. name = filename;
  348. if (replace_names) {
  349. for (size_t i = origsize; i < m_nodenames.size(); i++) {
  350. std::string &node_name = m_nodenames[i];
  351. StringMap::iterator it = replace_names->find(node_name);
  352. if (it != replace_names->end())
  353. node_name = it->second;
  354. }
  355. }
  356. if (ndef)
  357. ndef->pendNodeResolve(this);
  358. return true;
  359. }
  360. bool Schematic::saveSchematicToFile(const std::string &filename,
  361. const NodeDefManager *ndef)
  362. {
  363. MapNode *orig_schemdata = schemdata;
  364. std::vector<std::string> ndef_nodenames;
  365. std::vector<std::string> *names;
  366. if (m_resolve_done && ndef == NULL)
  367. ndef = m_ndef;
  368. if (ndef) {
  369. names = &ndef_nodenames;
  370. u32 volume = size.X * size.Y * size.Z;
  371. schemdata = new MapNode[volume];
  372. for (u32 i = 0; i != volume; i++)
  373. schemdata[i] = orig_schemdata[i];
  374. generate_nodelist_and_update_ids(schemdata, volume, names, ndef);
  375. } else { // otherwise, use the names we have on hand in the list
  376. names = &m_nodenames;
  377. }
  378. std::ostringstream os(std::ios_base::binary);
  379. bool status = serializeToMts(&os, *names);
  380. if (ndef) {
  381. delete []schemdata;
  382. schemdata = orig_schemdata;
  383. }
  384. if (!status)
  385. return false;
  386. return fs::safeWriteToFile(filename, os.str());
  387. }
  388. bool Schematic::getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2)
  389. {
  390. MMVManip *vm = new MMVManip(map);
  391. v3s16 bp1 = getNodeBlockPos(p1);
  392. v3s16 bp2 = getNodeBlockPos(p2);
  393. vm->initialEmerge(bp1, bp2);
  394. size = p2 - p1 + 1;
  395. slice_probs = new u8[size.Y];
  396. for (s16 y = 0; y != size.Y; y++)
  397. slice_probs[y] = MTSCHEM_PROB_ALWAYS;
  398. schemdata = new MapNode[size.X * size.Y * size.Z];
  399. u32 i = 0;
  400. for (s16 z = p1.Z; z <= p2.Z; z++)
  401. for (s16 y = p1.Y; y <= p2.Y; y++) {
  402. u32 vi = vm->m_area.index(p1.X, y, z);
  403. for (s16 x = p1.X; x <= p2.X; x++, i++, vi++) {
  404. schemdata[i] = vm->m_data[vi];
  405. schemdata[i].param1 = MTSCHEM_PROB_ALWAYS;
  406. }
  407. }
  408. delete vm;
  409. return true;
  410. }
  411. void Schematic::applyProbabilities(v3s16 p0,
  412. std::vector<std::pair<v3s16, u8> > *plist,
  413. std::vector<std::pair<s16, u8> > *splist)
  414. {
  415. for (size_t i = 0; i != plist->size(); i++) {
  416. v3s16 p = (*plist)[i].first - p0;
  417. int index = p.Z * (size.Y * size.X) + p.Y * size.X + p.X;
  418. if (index < size.Z * size.Y * size.X) {
  419. u8 prob = (*plist)[i].second;
  420. schemdata[index].param1 = prob;
  421. // trim unnecessary node names from schematic
  422. if (prob == MTSCHEM_PROB_NEVER)
  423. schemdata[index].setContent(CONTENT_AIR);
  424. }
  425. }
  426. for (size_t i = 0; i != splist->size(); i++) {
  427. s16 y = (*splist)[i].first - p0.Y;
  428. slice_probs[y] = (*splist)[i].second;
  429. }
  430. }
  431. void generate_nodelist_and_update_ids(MapNode *nodes, size_t nodecount,
  432. std::vector<std::string> *usednodes, const NodeDefManager *ndef)
  433. {
  434. std::unordered_map<content_t, content_t> nodeidmap;
  435. content_t numids = 0;
  436. for (size_t i = 0; i != nodecount; i++) {
  437. content_t id;
  438. content_t c = nodes[i].getContent();
  439. std::unordered_map<content_t, content_t>::const_iterator it = nodeidmap.find(c);
  440. if (it == nodeidmap.end()) {
  441. id = numids;
  442. numids++;
  443. usednodes->push_back(ndef->get(c).name);
  444. nodeidmap.insert(std::make_pair(c, id));
  445. } else {
  446. id = it->second;
  447. }
  448. nodes[i].setContent(id);
  449. }
  450. }