mg_decoration.cpp 11 KB

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