mg_decoration.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*
  2. Minetest
  3. Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
  4. Copyright (C) 2015-2017 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. FlagDesc flagdesc_deco[] = {
  26. {"place_center_x", DECO_PLACE_CENTER_X},
  27. {"place_center_y", DECO_PLACE_CENTER_Y},
  28. {"place_center_z", DECO_PLACE_CENTER_Z},
  29. {"force_placement", DECO_FORCE_PLACEMENT},
  30. {"liquid_surface", DECO_LIQUID_SURFACE},
  31. {NULL, 0}
  32. };
  33. ///////////////////////////////////////////////////////////////////////////////
  34. DecorationManager::DecorationManager(IGameDef *gamedef) :
  35. ObjDefManager(gamedef, OBJDEF_DECORATION)
  36. {
  37. }
  38. size_t DecorationManager::placeAllDecos(Mapgen *mg, u32 blockseed,
  39. v3s16 nmin, v3s16 nmax, s16 deco_zero_level)
  40. {
  41. size_t nplaced = 0;
  42. for (size_t i = 0; i != m_objects.size(); i++) {
  43. Decoration *deco = (Decoration *)m_objects[i];
  44. if (!deco)
  45. continue;
  46. nplaced += deco->placeDeco(mg, blockseed, nmin, nmax, deco_zero_level);
  47. blockseed++;
  48. }
  49. return nplaced;
  50. }
  51. ///////////////////////////////////////////////////////////////////////////////
  52. void Decoration::resolveNodeNames()
  53. {
  54. getIdsFromNrBacklog(&c_place_on);
  55. getIdsFromNrBacklog(&c_spawnby);
  56. }
  57. bool Decoration::canPlaceDecoration(MMVManip *vm, v3s16 p)
  58. {
  59. // Check if the decoration can be placed on this node
  60. u32 vi = vm->m_area.index(p);
  61. if (!CONTAINS(c_place_on, vm->m_data[vi].getContent()))
  62. return false;
  63. // Don't continue if there are no spawnby constraints
  64. if (nspawnby == -1)
  65. return true;
  66. int nneighs = 0;
  67. static const v3s16 dirs[16] = {
  68. v3s16( 0, 0, 1),
  69. v3s16( 0, 0, -1),
  70. v3s16( 1, 0, 0),
  71. v3s16(-1, 0, 0),
  72. v3s16( 1, 0, 1),
  73. v3s16(-1, 0, 1),
  74. v3s16(-1, 0, -1),
  75. v3s16( 1, 0, -1),
  76. v3s16( 0, 1, 1),
  77. v3s16( 0, 1, -1),
  78. v3s16( 1, 1, 0),
  79. v3s16(-1, 1, 0),
  80. v3s16( 1, 1, 1),
  81. v3s16(-1, 1, 1),
  82. v3s16(-1, 1, -1),
  83. v3s16( 1, 1, -1)
  84. };
  85. // Check these 16 neighbouring nodes for enough spawnby nodes
  86. for (size_t i = 0; i != ARRLEN(dirs); i++) {
  87. u32 index = vm->m_area.index(p + dirs[i]);
  88. if (!vm->m_area.contains(index))
  89. continue;
  90. if (CONTAINS(c_spawnby, vm->m_data[index].getContent()))
  91. nneighs++;
  92. }
  93. if (nneighs < nspawnby)
  94. return false;
  95. return true;
  96. }
  97. size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed,
  98. v3s16 nmin, v3s16 nmax, s16 deco_zero_level)
  99. {
  100. // Decoration y_min / y_max is displaced by deco_zero_level or remains
  101. // unchanged. Any decoration with a limit at +-MAX_MAP_GENERATION_LIMIT is
  102. // considered to have that limit at +-infinity, so we do not alter that limit.
  103. s32 y_min_disp = (y_min <= -MAX_MAP_GENERATION_LIMIT) ?
  104. -MAX_MAP_GENERATION_LIMIT : y_min + deco_zero_level;
  105. s32 y_max_disp = (y_max >= MAX_MAP_GENERATION_LIMIT) ?
  106. MAX_MAP_GENERATION_LIMIT : y_max + deco_zero_level;
  107. PcgRandom ps(blockseed + 53);
  108. int carea_size = nmax.X - nmin.X + 1;
  109. // Divide area into parts
  110. // If chunksize is changed it may no longer be divisable by sidelen
  111. if (carea_size % sidelen)
  112. sidelen = carea_size;
  113. s16 divlen = carea_size / sidelen;
  114. int area = sidelen * sidelen;
  115. for (s16 z0 = 0; z0 < divlen; z0++)
  116. for (s16 x0 = 0; x0 < divlen; x0++) {
  117. v2s16 p2d_center( // Center position of part of division
  118. nmin.X + sidelen / 2 + sidelen * x0,
  119. nmin.Z + sidelen / 2 + sidelen * z0
  120. );
  121. v2s16 p2d_min( // Minimum edge of part of division
  122. nmin.X + sidelen * x0,
  123. nmin.Z + sidelen * z0
  124. );
  125. v2s16 p2d_max( // Maximum edge of part of division
  126. nmin.X + sidelen + sidelen * x0 - 1,
  127. nmin.Z + sidelen + sidelen * z0 - 1
  128. );
  129. // Amount of decorations
  130. float nval = (flags & DECO_USE_NOISE) ?
  131. NoisePerlin2D(&np, p2d_center.X, p2d_center.Y, mapseed) :
  132. fill_ratio;
  133. u32 deco_count = 0;
  134. float deco_count_f = (float)area * nval;
  135. if (deco_count_f >= 1.f) {
  136. deco_count = deco_count_f;
  137. } else if (deco_count_f > 0.f) {
  138. // For low density decorations calculate a chance for 1 decoration
  139. if (ps.range(1000) <= deco_count_f * 1000.f)
  140. deco_count = 1;
  141. }
  142. for (u32 i = 0; i < deco_count; i++) {
  143. s16 x = ps.range(p2d_min.X, p2d_max.X);
  144. s16 z = ps.range(p2d_min.Y, p2d_max.Y);
  145. int mapindex = carea_size * (z - nmin.Z) + (x - nmin.X);
  146. s16 y = -MAX_MAP_GENERATION_LIMIT;
  147. if (flags & DECO_LIQUID_SURFACE)
  148. y = mg->findLiquidSurface(v2s16(x, z), nmin.Y, nmax.Y);
  149. else if (mg->heightmap)
  150. y = mg->heightmap[mapindex];
  151. else
  152. y = mg->findGroundLevel(v2s16(x, z), nmin.Y, nmax.Y);
  153. if (y < y_min_disp || y > y_max_disp || y < nmin.Y || y > nmax.Y)
  154. continue;
  155. if (y + getHeight() > mg->vm->m_area.MaxEdge.Y) {
  156. continue;
  157. #if 0
  158. printf("Decoration at (%d %d %d) cut off\n", x, y, z);
  159. //add to queue
  160. MutexAutoLock cutofflock(cutoff_mutex);
  161. cutoffs.push_back(CutoffData(x, y, z, height));
  162. #endif
  163. }
  164. if (mg->biomemap && !biomes.empty()) {
  165. std::unordered_set<u8>::const_iterator iter =
  166. biomes.find(mg->biomemap[mapindex]);
  167. if (iter == biomes.end())
  168. continue;
  169. }
  170. v3s16 pos(x, y, z);
  171. if (generate(mg->vm, &ps, pos))
  172. mg->gennotify.addEvent(GENNOTIFY_DECORATION, pos, index);
  173. }
  174. }
  175. return 0;
  176. }
  177. #if 0
  178. void Decoration::placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
  179. {
  180. PcgRandom pr(blockseed + 53);
  181. std::vector<CutoffData> handled_cutoffs;
  182. // Copy over the cutoffs we're interested in so we don't needlessly hold a lock
  183. {
  184. MutexAutoLock cutofflock(cutoff_mutex);
  185. for (std::list<CutoffData>::iterator i = cutoffs.begin();
  186. i != cutoffs.end(); ++i) {
  187. CutoffData cutoff = *i;
  188. v3s16 p = cutoff.p;
  189. s16 height = cutoff.height;
  190. if (p.X < nmin.X || p.X > nmax.X ||
  191. p.Z < nmin.Z || p.Z > nmax.Z)
  192. continue;
  193. if (p.Y + height < nmin.Y || p.Y > nmax.Y)
  194. continue;
  195. handled_cutoffs.push_back(cutoff);
  196. }
  197. }
  198. // Generate the cutoffs
  199. for (size_t i = 0; i != handled_cutoffs.size(); i++) {
  200. v3s16 p = handled_cutoffs[i].p;
  201. s16 height = handled_cutoffs[i].height;
  202. if (p.Y + height > nmax.Y) {
  203. //printf("Decoration at (%d %d %d) cut off again!\n", p.X, p.Y, p.Z);
  204. cuttoffs.push_back(v3s16(p.X, p.Y, p.Z));
  205. }
  206. generate(mg, &pr, nmax.Y, nmin.Y - p.Y, v3s16(p.X, nmin.Y, p.Z));
  207. }
  208. // Remove cutoffs that were handled from the cutoff list
  209. {
  210. MutexAutoLock cutofflock(cutoff_mutex);
  211. for (std::list<CutoffData>::iterator i = cutoffs.begin();
  212. i != cutoffs.end(); ++i) {
  213. for (size_t j = 0; j != handled_cutoffs.size(); j++) {
  214. CutoffData coff = *i;
  215. if (coff.p == handled_cutoffs[j].p)
  216. i = cutoffs.erase(i);
  217. }
  218. }
  219. }
  220. }
  221. #endif
  222. ///////////////////////////////////////////////////////////////////////////////
  223. void DecoSimple::resolveNodeNames()
  224. {
  225. Decoration::resolveNodeNames();
  226. getIdsFromNrBacklog(&c_decos);
  227. }
  228. size_t DecoSimple::generate(MMVManip *vm, PcgRandom *pr, v3s16 p)
  229. {
  230. // Don't bother if there aren't any decorations to place
  231. if (c_decos.empty())
  232. return 0;
  233. if (!canPlaceDecoration(vm, p))
  234. return 0;
  235. content_t c_place = c_decos[pr->range(0, c_decos.size() - 1)];
  236. s16 height = (deco_height_max > 0) ?
  237. pr->range(deco_height, deco_height_max) : deco_height;
  238. bool force_placement = (flags & DECO_FORCE_PLACEMENT);
  239. const v3s16 &em = vm->m_area.getExtent();
  240. u32 vi = vm->m_area.index(p);
  241. for (int i = 0; i < height; i++) {
  242. vm->m_area.add_y(em, vi, 1);
  243. content_t c = vm->m_data[vi].getContent();
  244. if (c != CONTENT_AIR && c != CONTENT_IGNORE &&
  245. !force_placement)
  246. break;
  247. vm->m_data[vi] = MapNode(c_place, 0, deco_param2);
  248. }
  249. return 1;
  250. }
  251. int DecoSimple::getHeight()
  252. {
  253. return (deco_height_max > 0) ? deco_height_max : deco_height;
  254. }
  255. ///////////////////////////////////////////////////////////////////////////////
  256. size_t DecoSchematic::generate(MMVManip *vm, PcgRandom *pr, v3s16 p)
  257. {
  258. // Schematic could have been unloaded but not the decoration
  259. // In this case generate() does nothing (but doesn't *fail*)
  260. if (schematic == NULL)
  261. return 0;
  262. if (!canPlaceDecoration(vm, p))
  263. return 0;
  264. if (flags & DECO_PLACE_CENTER_X)
  265. p.X -= (schematic->size.X - 1) / 2;
  266. if (flags & DECO_PLACE_CENTER_Y)
  267. p.Y -= (schematic->size.Y - 1) / 2;
  268. if (flags & DECO_PLACE_CENTER_Z)
  269. p.Z -= (schematic->size.Z - 1) / 2;
  270. Rotation rot = (rotation == ROTATE_RAND) ?
  271. (Rotation)pr->range(ROTATE_0, ROTATE_270) : rotation;
  272. bool force_placement = (flags & DECO_FORCE_PLACEMENT);
  273. schematic->blitToVManip(vm, p, rot, force_placement);
  274. return 1;
  275. }
  276. int DecoSchematic::getHeight()
  277. {
  278. // Account for a schematic being sunk into the ground by flag.
  279. // When placed normally account for how a schematic is placed
  280. // sunk 1 node into the ground.
  281. return (flags & DECO_PLACE_CENTER_Y) ?
  282. (schematic->size.Y - 1) / 2 : schematic->size.Y - 1;
  283. }