mg_decoration.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  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 "mg_decoration.h"
  18. #include "mg_schematic.h"
  19. #include "mapgen.h"
  20. #include "noise.h"
  21. #include "map.h"
  22. #include "log.h"
  23. #include "util/numeric.h"
  24. #include <algorithm>
  25. #include <vector>
  26. FlagDesc flagdesc_deco[] = {
  27. {"place_center_x", DECO_PLACE_CENTER_X},
  28. {"place_center_y", DECO_PLACE_CENTER_Y},
  29. {"place_center_z", DECO_PLACE_CENTER_Z},
  30. {"force_placement", DECO_FORCE_PLACEMENT},
  31. {"liquid_surface", DECO_LIQUID_SURFACE},
  32. {"all_floors", DECO_ALL_FLOORS},
  33. {"all_ceilings", DECO_ALL_CEILINGS},
  34. {NULL, 0}
  35. };
  36. ///////////////////////////////////////////////////////////////////////////////
  37. DecorationManager::DecorationManager(IGameDef *gamedef) :
  38. ObjDefManager(gamedef, OBJDEF_DECORATION)
  39. {
  40. }
  41. size_t DecorationManager::placeAllDecos(Mapgen *mg, u32 blockseed,
  42. v3s16 nmin, v3s16 nmax)
  43. {
  44. size_t nplaced = 0;
  45. for (size_t i = 0; i != m_objects.size(); i++) {
  46. Decoration *deco = (Decoration *)m_objects[i];
  47. if (!deco)
  48. continue;
  49. nplaced += deco->placeDeco(mg, blockseed, nmin, nmax);
  50. blockseed++;
  51. }
  52. return nplaced;
  53. }
  54. DecorationManager *DecorationManager::clone() const
  55. {
  56. auto mgr = new DecorationManager();
  57. ObjDefManager::cloneTo(mgr);
  58. return mgr;
  59. }
  60. ///////////////////////////////////////////////////////////////////////////////
  61. void Decoration::resolveNodeNames()
  62. {
  63. getIdsFromNrBacklog(&c_place_on);
  64. getIdsFromNrBacklog(&c_spawnby);
  65. }
  66. bool Decoration::canPlaceDecoration(MMVManip *vm, v3s16 p)
  67. {
  68. // Note that `p` refers to the node the decoration will be placed ontop of,
  69. // not to the decoration itself.
  70. // Check if the decoration can be placed on this node
  71. u32 vi = vm->m_area.index(p);
  72. if (!CONTAINS(c_place_on, vm->m_data[vi].getContent()))
  73. return false;
  74. // Don't continue if there are no spawnby constraints
  75. if (nspawnby == -1)
  76. return true;
  77. int nneighs = 0;
  78. static const v3s16 dirs[8] = {
  79. v3s16( 0, 1, 1),
  80. v3s16( 0, 1, -1),
  81. v3s16( 1, 1, 0),
  82. v3s16(-1, 1, 0),
  83. v3s16( 1, 1, 1),
  84. v3s16(-1, 1, 1),
  85. v3s16(-1, 1, -1),
  86. v3s16( 1, 1, -1)
  87. };
  88. // Check these 16 neighboring nodes for enough spawnby nodes
  89. for (size_t i = 0; i != ARRLEN(dirs); i++) {
  90. u32 index = vm->m_area.index(p + dirs[i]);
  91. if (!vm->m_area.contains(index))
  92. continue;
  93. if (CONTAINS(c_spawnby, vm->m_data[index].getContent()))
  94. nneighs++;
  95. }
  96. if (check_offset != 0) {
  97. const v3s16 dir_offset(0, check_offset, 0);
  98. for (size_t i = 0; i != ARRLEN(dirs); i++) {
  99. u32 index = vm->m_area.index(p + dirs[i] + dir_offset);
  100. if (!vm->m_area.contains(index))
  101. continue;
  102. if (CONTAINS(c_spawnby, vm->m_data[index].getContent()))
  103. nneighs++;
  104. }
  105. }
  106. if (nneighs < nspawnby)
  107. return false;
  108. return true;
  109. }
  110. size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
  111. {
  112. PcgRandom ps(blockseed + 53);
  113. int carea_size = nmax.X - nmin.X + 1;
  114. // Divide area into parts
  115. // If chunksize is changed it may no longer be divisable by sidelen
  116. if (carea_size % sidelen)
  117. sidelen = carea_size;
  118. s16 divlen = carea_size / sidelen;
  119. int area = sidelen * sidelen;
  120. for (s16 z0 = 0; z0 < divlen; z0++)
  121. for (s16 x0 = 0; x0 < divlen; x0++) {
  122. v2s16 p2d_center( // Center position of part of division
  123. nmin.X + sidelen / 2 + sidelen * x0,
  124. nmin.Z + sidelen / 2 + sidelen * z0
  125. );
  126. v2s16 p2d_min( // Minimum edge of part of division
  127. nmin.X + sidelen * x0,
  128. nmin.Z + sidelen * z0
  129. );
  130. v2s16 p2d_max( // Maximum edge of part of division
  131. nmin.X + sidelen + sidelen * x0 - 1,
  132. nmin.Z + sidelen + sidelen * z0 - 1
  133. );
  134. bool cover = false;
  135. // Amount of decorations
  136. float nval = (flags & DECO_USE_NOISE) ?
  137. NoisePerlin2D(&np, p2d_center.X, p2d_center.Y, mapseed) :
  138. fill_ratio;
  139. u32 deco_count = 0;
  140. if (nval >= 10.0f) {
  141. // Complete coverage. Disable random placement to avoid
  142. // redundant multiple placements at one position.
  143. cover = true;
  144. deco_count = area;
  145. } else {
  146. float deco_count_f = (float)area * nval;
  147. if (deco_count_f >= 1.0f) {
  148. deco_count = deco_count_f;
  149. } else if (deco_count_f > 0.0f) {
  150. // For very low density calculate a chance for 1 decoration
  151. if (ps.range(1000) <= deco_count_f * 1000.0f)
  152. deco_count = 1;
  153. }
  154. }
  155. s16 x = p2d_min.X - 1;
  156. s16 z = p2d_min.Y;
  157. for (u32 i = 0; i < deco_count; i++) {
  158. if (!cover) {
  159. x = ps.range(p2d_min.X, p2d_max.X);
  160. z = ps.range(p2d_min.Y, p2d_max.Y);
  161. } else {
  162. x++;
  163. if (x == p2d_max.X + 1) {
  164. z++;
  165. x = p2d_min.X;
  166. }
  167. }
  168. int mapindex = carea_size * (z - nmin.Z) + (x - nmin.X);
  169. if ((flags & DECO_ALL_FLOORS) ||
  170. (flags & DECO_ALL_CEILINGS)) {
  171. // All-surfaces decorations
  172. // Check biome of column
  173. if (mg->biomemap && !biomes.empty()) {
  174. auto iter = biomes.find(mg->biomemap[mapindex]);
  175. if (iter == biomes.end())
  176. continue;
  177. }
  178. // Get all floors and ceilings in node column
  179. u16 size = (nmax.Y - nmin.Y + 1) / 2;
  180. std::vector<s16> floors;
  181. std::vector<s16> ceilings;
  182. floors.reserve(size);
  183. ceilings.reserve(size);
  184. mg->getSurfaces(v2s16(x, z), nmin.Y, nmax.Y, floors, ceilings);
  185. if (flags & DECO_ALL_FLOORS) {
  186. // Floor decorations
  187. for (const s16 y : floors) {
  188. if (y < y_min || y > y_max)
  189. continue;
  190. v3s16 pos(x, y, z);
  191. if (generate(mg->vm, &ps, pos, false))
  192. mg->gennotify.addDecorationEvent(pos, index);
  193. }
  194. }
  195. if (flags & DECO_ALL_CEILINGS) {
  196. // Ceiling decorations
  197. for (const s16 y : ceilings) {
  198. if (y < y_min || y > y_max)
  199. continue;
  200. v3s16 pos(x, y, z);
  201. if (generate(mg->vm, &ps, pos, true))
  202. mg->gennotify.addDecorationEvent(pos, index);
  203. }
  204. }
  205. } else { // Heightmap decorations
  206. s16 y = -MAX_MAP_GENERATION_LIMIT;
  207. if (flags & DECO_LIQUID_SURFACE)
  208. y = mg->findLiquidSurface(v2s16(x, z), nmin.Y, nmax.Y);
  209. else if (mg->heightmap)
  210. y = mg->heightmap[mapindex];
  211. else
  212. y = mg->findGroundLevel(v2s16(x, z), nmin.Y, nmax.Y);
  213. if (y < y_min || y > y_max || y < nmin.Y || y > nmax.Y)
  214. continue;
  215. if (mg->biomemap && !biomes.empty()) {
  216. auto iter = biomes.find(mg->biomemap[mapindex]);
  217. if (iter == biomes.end())
  218. continue;
  219. }
  220. v3s16 pos(x, y, z);
  221. if (generate(mg->vm, &ps, pos, false))
  222. mg->gennotify.addDecorationEvent(pos, index);
  223. }
  224. }
  225. }
  226. return 0;
  227. }
  228. void Decoration::cloneTo(Decoration *def) const
  229. {
  230. ObjDef::cloneTo(def);
  231. def->flags = flags;
  232. def->mapseed = mapseed;
  233. def->c_place_on = c_place_on;
  234. def->check_offset = check_offset;
  235. def->sidelen = sidelen;
  236. def->y_min = y_min;
  237. def->y_max = y_max;
  238. def->fill_ratio = fill_ratio;
  239. def->np = np;
  240. def->c_spawnby = c_spawnby;
  241. def->nspawnby = nspawnby;
  242. def->place_offset_y = place_offset_y;
  243. def->biomes = biomes;
  244. }
  245. ///////////////////////////////////////////////////////////////////////////////
  246. ObjDef *DecoSimple::clone() const
  247. {
  248. auto def = new DecoSimple();
  249. Decoration::cloneTo(def);
  250. def->c_decos = c_decos;
  251. def->deco_height = deco_height;
  252. def->deco_height_max = deco_height_max;
  253. def->deco_param2 = deco_param2;
  254. def->deco_param2_max = deco_param2_max;
  255. return def;
  256. }
  257. void DecoSimple::resolveNodeNames()
  258. {
  259. Decoration::resolveNodeNames();
  260. getIdsFromNrBacklog(&c_decos);
  261. }
  262. size_t DecoSimple::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling)
  263. {
  264. // Don't bother if there aren't any decorations to place
  265. if (c_decos.empty())
  266. return 0;
  267. if (!canPlaceDecoration(vm, p))
  268. return 0;
  269. // Check for placement outside the voxelmanip volume
  270. if (ceiling) {
  271. // Ceiling decorations
  272. // 'place offset y' is inverted
  273. if (p.Y - place_offset_y - std::max(deco_height, deco_height_max) <
  274. vm->m_area.MinEdge.Y)
  275. return 0;
  276. if (p.Y - 1 - place_offset_y > vm->m_area.MaxEdge.Y)
  277. return 0;
  278. } else { // Heightmap and floor decorations
  279. if (p.Y + place_offset_y + std::max(deco_height, deco_height_max) >
  280. vm->m_area.MaxEdge.Y)
  281. return 0;
  282. if (p.Y + 1 + place_offset_y < vm->m_area.MinEdge.Y)
  283. return 0;
  284. }
  285. content_t c_place = c_decos[pr->range(0, c_decos.size() - 1)];
  286. s16 height = (deco_height_max > 0) ?
  287. pr->range(deco_height, deco_height_max) : deco_height;
  288. u8 param2 = (deco_param2_max > 0) ?
  289. pr->range(deco_param2, deco_param2_max) : deco_param2;
  290. bool force_placement = (flags & DECO_FORCE_PLACEMENT);
  291. const v3s16 &em = vm->m_area.getExtent();
  292. u32 vi = vm->m_area.index(p);
  293. if (ceiling) {
  294. // Ceiling decorations
  295. // 'place offset y' is inverted
  296. VoxelArea::add_y(em, vi, -place_offset_y);
  297. for (int i = 0; i < height; i++) {
  298. VoxelArea::add_y(em, vi, -1);
  299. content_t c = vm->m_data[vi].getContent();
  300. if (c != CONTENT_AIR && c != CONTENT_IGNORE && !force_placement)
  301. break;
  302. vm->m_data[vi] = MapNode(c_place, 0, param2);
  303. }
  304. } else { // Heightmap and floor decorations
  305. VoxelArea::add_y(em, vi, place_offset_y);
  306. for (int i = 0; i < height; i++) {
  307. VoxelArea::add_y(em, vi, 1);
  308. content_t c = vm->m_data[vi].getContent();
  309. if (c != CONTENT_AIR && c != CONTENT_IGNORE && !force_placement)
  310. break;
  311. vm->m_data[vi] = MapNode(c_place, 0, param2);
  312. }
  313. }
  314. return 1;
  315. }
  316. ///////////////////////////////////////////////////////////////////////////////
  317. DecoSchematic::~DecoSchematic()
  318. {
  319. if (was_cloned)
  320. delete schematic;
  321. }
  322. ObjDef *DecoSchematic::clone() const
  323. {
  324. auto def = new DecoSchematic();
  325. Decoration::cloneTo(def);
  326. NodeResolver::cloneTo(def);
  327. def->rotation = rotation;
  328. /* FIXME: We do not own this schematic, yet we only have a pointer to it
  329. * and not a handle. We are left with no option but to clone it ourselves.
  330. * This is a waste of memory and should be replaced with an alternative
  331. * approach sometime. */
  332. def->schematic = dynamic_cast<Schematic*>(schematic->clone());
  333. def->was_cloned = true;
  334. return def;
  335. }
  336. size_t DecoSchematic::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling)
  337. {
  338. // Schematic could have been unloaded but not the decoration
  339. // In this case generate() does nothing (but doesn't *fail*)
  340. if (schematic == NULL)
  341. return 0;
  342. if (!canPlaceDecoration(vm, p))
  343. return 0;
  344. if (flags & DECO_PLACE_CENTER_Y) {
  345. p.Y -= (schematic->size.Y - 1) / 2;
  346. } else {
  347. // Only apply 'place offset y' if not 'deco place center y'
  348. if (ceiling)
  349. // Shift down so that schematic top layer is level with ceiling
  350. // 'place offset y' is inverted
  351. p.Y -= (place_offset_y + schematic->size.Y - 1);
  352. else
  353. p.Y += place_offset_y;
  354. }
  355. // Check schematic top and base are in voxelmanip
  356. if (p.Y + schematic->size.Y - 1 > vm->m_area.MaxEdge.Y)
  357. return 0;
  358. if (p.Y < vm->m_area.MinEdge.Y)
  359. return 0;
  360. Rotation rot = (rotation == ROTATE_RAND) ?
  361. (Rotation)pr->range(ROTATE_0, ROTATE_270) : rotation;
  362. if (flags & DECO_PLACE_CENTER_X) {
  363. if (rot == ROTATE_0 || rot == ROTATE_180)
  364. p.X -= (schematic->size.X - 1) / 2;
  365. else
  366. p.Z -= (schematic->size.X - 1) / 2;
  367. }
  368. if (flags & DECO_PLACE_CENTER_Z) {
  369. if (rot == ROTATE_0 || rot == ROTATE_180)
  370. p.Z -= (schematic->size.Z - 1) / 2;
  371. else
  372. p.X -= (schematic->size.Z - 1) / 2;
  373. }
  374. bool force_placement = (flags & DECO_FORCE_PLACEMENT);
  375. schematic->blitToVManip(vm, p, rot, force_placement);
  376. return 1;
  377. }