Final Minetest - Please use Linux & Windows build kits at: https://downloads.minetest.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mg_ore.cpp 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  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_ore.h"
  18. #include "mapgen.h"
  19. #include "noise.h"
  20. #include "map.h"
  21. #include "log.h"
  22. #include <algorithm>
  23. FlagDesc flagdesc_ore[] = {
  24. {"absheight", OREFLAG_ABSHEIGHT}, // Non-functional
  25. {"puff_cliffs", OREFLAG_PUFF_CLIFFS},
  26. {"puff_additive_composition", OREFLAG_PUFF_ADDITIVE},
  27. {NULL, 0}
  28. };
  29. ///////////////////////////////////////////////////////////////////////////////
  30. OreManager::OreManager(IGameDef *gamedef) :
  31. ObjDefManager(gamedef, OBJDEF_ORE)
  32. {
  33. }
  34. size_t OreManager::placeAllOres(Mapgen *mg, u32 blockseed,
  35. v3s16 nmin, v3s16 nmax, s16 ore_zero_level)
  36. {
  37. size_t nplaced = 0;
  38. for (size_t i = 0; i != m_objects.size(); i++) {
  39. Ore *ore = (Ore *)m_objects[i];
  40. if (!ore)
  41. continue;
  42. nplaced += ore->placeOre(mg, blockseed, nmin, nmax, ore_zero_level);
  43. blockseed++;
  44. }
  45. return nplaced;
  46. }
  47. void OreManager::clear()
  48. {
  49. for (size_t i = 0; i < m_objects.size(); i++) {
  50. Ore *ore = (Ore *)m_objects[i];
  51. delete ore;
  52. }
  53. m_objects.clear();
  54. }
  55. ///////////////////////////////////////////////////////////////////////////////
  56. Ore::~Ore()
  57. {
  58. delete noise;
  59. }
  60. void Ore::resolveNodeNames()
  61. {
  62. getIdFromNrBacklog(&c_ore, "", CONTENT_AIR);
  63. getIdsFromNrBacklog(&c_wherein);
  64. }
  65. size_t Ore::placeOre(Mapgen *mg, u32 blockseed,
  66. v3s16 nmin, v3s16 nmax, s16 ore_zero_level)
  67. {
  68. // Ore y_min / y_max is displaced by ore_zero_level or remains unchanged.
  69. // Any ore with a limit at +-MAX_MAP_GENERATION_LIMIT is considered to have
  70. // that limit at +-infinity, so we do not alter that limit.
  71. s32 y_min_disp = (y_min <= -MAX_MAP_GENERATION_LIMIT) ?
  72. -MAX_MAP_GENERATION_LIMIT : y_min + ore_zero_level;
  73. s32 y_max_disp = (y_max >= MAX_MAP_GENERATION_LIMIT) ?
  74. MAX_MAP_GENERATION_LIMIT : y_max + ore_zero_level;
  75. if (nmin.Y > y_max_disp || nmax.Y < y_min_disp)
  76. return 0;
  77. int actual_ymin = MYMAX(nmin.Y, y_min_disp);
  78. int actual_ymax = MYMIN(nmax.Y, y_max_disp);
  79. if (clust_size >= actual_ymax - actual_ymin + 1)
  80. return 0;
  81. nmin.Y = actual_ymin;
  82. nmax.Y = actual_ymax;
  83. generate(mg->vm, mg->seed, blockseed, nmin, nmax, mg->biomemap);
  84. return 1;
  85. }
  86. ///////////////////////////////////////////////////////////////////////////////
  87. void OreScatter::generate(MMVManip *vm, int mapseed, u32 blockseed,
  88. v3s16 nmin, v3s16 nmax, u8 *biomemap)
  89. {
  90. PcgRandom pr(blockseed);
  91. MapNode n_ore(c_ore, 0, ore_param2);
  92. u32 sizex = (nmax.X - nmin.X + 1);
  93. u32 volume = (nmax.X - nmin.X + 1) *
  94. (nmax.Y - nmin.Y + 1) *
  95. (nmax.Z - nmin.Z + 1);
  96. u32 csize = clust_size;
  97. u32 cvolume = csize * csize * csize;
  98. u32 nclusters = volume / clust_scarcity;
  99. for (u32 i = 0; i != nclusters; i++) {
  100. int x0 = pr.range(nmin.X, nmax.X - csize + 1);
  101. int y0 = pr.range(nmin.Y, nmax.Y - csize + 1);
  102. int z0 = pr.range(nmin.Z, nmax.Z - csize + 1);
  103. if ((flags & OREFLAG_USE_NOISE) &&
  104. (NoisePerlin3D(&np, x0, y0, z0, mapseed) < nthresh))
  105. continue;
  106. if (biomemap && !biomes.empty()) {
  107. u32 index = sizex * (z0 - nmin.Z) + (x0 - nmin.X);
  108. std::unordered_set<u8>::const_iterator it = biomes.find(biomemap[index]);
  109. if (it == biomes.end())
  110. continue;
  111. }
  112. for (u32 z1 = 0; z1 != csize; z1++)
  113. for (u32 y1 = 0; y1 != csize; y1++)
  114. for (u32 x1 = 0; x1 != csize; x1++) {
  115. if (pr.range(1, cvolume) > clust_num_ores)
  116. continue;
  117. u32 i = vm->m_area.index(x0 + x1, y0 + y1, z0 + z1);
  118. if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
  119. continue;
  120. vm->m_data[i] = n_ore;
  121. }
  122. }
  123. }
  124. ///////////////////////////////////////////////////////////////////////////////
  125. void OreSheet::generate(MMVManip *vm, int mapseed, u32 blockseed,
  126. v3s16 nmin, v3s16 nmax, u8 *biomemap)
  127. {
  128. PcgRandom pr(blockseed + 4234);
  129. MapNode n_ore(c_ore, 0, ore_param2);
  130. u16 max_height = column_height_max;
  131. int y_start_min = nmin.Y + max_height;
  132. int y_start_max = nmax.Y - max_height;
  133. int y_start = y_start_min < y_start_max ?
  134. pr.range(y_start_min, y_start_max) :
  135. (y_start_min + y_start_max) / 2;
  136. if (!noise) {
  137. int sx = nmax.X - nmin.X + 1;
  138. int sz = nmax.Z - nmin.Z + 1;
  139. noise = new Noise(&np, 0, sx, sz);
  140. }
  141. noise->seed = mapseed + y_start;
  142. noise->perlinMap2D(nmin.X, nmin.Z);
  143. size_t index = 0;
  144. for (int z = nmin.Z; z <= nmax.Z; z++)
  145. for (int x = nmin.X; x <= nmax.X; x++, index++) {
  146. float noiseval = noise->result[index];
  147. if (noiseval < nthresh)
  148. continue;
  149. if (biomemap && !biomes.empty()) {
  150. std::unordered_set<u8>::const_iterator it = biomes.find(biomemap[index]);
  151. if (it == biomes.end())
  152. continue;
  153. }
  154. u16 height = pr.range(column_height_min, column_height_max);
  155. int ymidpoint = y_start + noiseval;
  156. int y0 = MYMAX(nmin.Y, ymidpoint - height * (1 - column_midpoint_factor));
  157. int y1 = MYMIN(nmax.Y, y0 + height - 1);
  158. for (int y = y0; y <= y1; y++) {
  159. u32 i = vm->m_area.index(x, y, z);
  160. if (!vm->m_area.contains(i))
  161. continue;
  162. if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
  163. continue;
  164. vm->m_data[i] = n_ore;
  165. }
  166. }
  167. }
  168. ///////////////////////////////////////////////////////////////////////////////
  169. OrePuff::OrePuff() :
  170. Ore()
  171. {
  172. }
  173. OrePuff::~OrePuff()
  174. {
  175. delete noise_puff_top;
  176. delete noise_puff_bottom;
  177. }
  178. void OrePuff::generate(MMVManip *vm, int mapseed, u32 blockseed,
  179. v3s16 nmin, v3s16 nmax, u8 *biomemap)
  180. {
  181. PcgRandom pr(blockseed + 4234);
  182. MapNode n_ore(c_ore, 0, ore_param2);
  183. int y_start = pr.range(nmin.Y, nmax.Y);
  184. if (!noise) {
  185. int sx = nmax.X - nmin.X + 1;
  186. int sz = nmax.Z - nmin.Z + 1;
  187. noise = new Noise(&np, 0, sx, sz);
  188. noise_puff_top = new Noise(&np_puff_top, 0, sx, sz);
  189. noise_puff_bottom = new Noise(&np_puff_bottom, 0, sx, sz);
  190. }
  191. noise->seed = mapseed + y_start;
  192. noise->perlinMap2D(nmin.X, nmin.Z);
  193. bool noise_generated = false;
  194. size_t index = 0;
  195. for (int z = nmin.Z; z <= nmax.Z; z++)
  196. for (int x = nmin.X; x <= nmax.X; x++, index++) {
  197. float noiseval = noise->result[index];
  198. if (noiseval < nthresh)
  199. continue;
  200. if (biomemap && !biomes.empty()) {
  201. std::unordered_set<u8>::const_iterator it = biomes.find(biomemap[index]);
  202. if (it == biomes.end())
  203. continue;
  204. }
  205. if (!noise_generated) {
  206. noise_generated = true;
  207. noise_puff_top->perlinMap2D(nmin.X, nmin.Z);
  208. noise_puff_bottom->perlinMap2D(nmin.X, nmin.Z);
  209. }
  210. float ntop = noise_puff_top->result[index];
  211. float nbottom = noise_puff_bottom->result[index];
  212. if (!(flags & OREFLAG_PUFF_CLIFFS)) {
  213. float ndiff = noiseval - nthresh;
  214. if (ndiff < 1.0f) {
  215. ntop *= ndiff;
  216. nbottom *= ndiff;
  217. }
  218. }
  219. int ymid = y_start;
  220. int y0 = ymid - nbottom;
  221. int y1 = ymid + ntop;
  222. if ((flags & OREFLAG_PUFF_ADDITIVE) && (y0 > y1))
  223. SWAP(int, y0, y1);
  224. for (int y = y0; y <= y1; y++) {
  225. u32 i = vm->m_area.index(x, y, z);
  226. if (!vm->m_area.contains(i))
  227. continue;
  228. if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
  229. continue;
  230. vm->m_data[i] = n_ore;
  231. }
  232. }
  233. }
  234. ///////////////////////////////////////////////////////////////////////////////
  235. void OreBlob::generate(MMVManip *vm, int mapseed, u32 blockseed,
  236. v3s16 nmin, v3s16 nmax, u8 *biomemap)
  237. {
  238. PcgRandom pr(blockseed + 2404);
  239. MapNode n_ore(c_ore, 0, ore_param2);
  240. u32 sizex = (nmax.X - nmin.X + 1);
  241. u32 volume = (nmax.X - nmin.X + 1) *
  242. (nmax.Y - nmin.Y + 1) *
  243. (nmax.Z - nmin.Z + 1);
  244. u32 csize = clust_size;
  245. u32 nblobs = volume / clust_scarcity;
  246. if (!noise)
  247. noise = new Noise(&np, mapseed, csize, csize, csize);
  248. for (u32 i = 0; i != nblobs; i++) {
  249. int x0 = pr.range(nmin.X, nmax.X - csize + 1);
  250. int y0 = pr.range(nmin.Y, nmax.Y - csize + 1);
  251. int z0 = pr.range(nmin.Z, nmax.Z - csize + 1);
  252. if (biomemap && !biomes.empty()) {
  253. u32 bmapidx = sizex * (z0 - nmin.Z) + (x0 - nmin.X);
  254. std::unordered_set<u8>::const_iterator it = biomes.find(biomemap[bmapidx]);
  255. if (it == biomes.end())
  256. continue;
  257. }
  258. bool noise_generated = false;
  259. noise->seed = blockseed + i;
  260. size_t index = 0;
  261. for (u32 z1 = 0; z1 != csize; z1++)
  262. for (u32 y1 = 0; y1 != csize; y1++)
  263. for (u32 x1 = 0; x1 != csize; x1++, index++) {
  264. u32 i = vm->m_area.index(x0 + x1, y0 + y1, z0 + z1);
  265. if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
  266. continue;
  267. // Lazily generate noise only if there's a chance of ore being placed
  268. // This simple optimization makes calls 6x faster on average
  269. if (!noise_generated) {
  270. noise_generated = true;
  271. noise->perlinMap3D(x0, y0, z0);
  272. }
  273. float noiseval = noise->result[index];
  274. float xdist = (s32)x1 - (s32)csize / 2;
  275. float ydist = (s32)y1 - (s32)csize / 2;
  276. float zdist = (s32)z1 - (s32)csize / 2;
  277. noiseval -= (sqrt(xdist * xdist + ydist * ydist + zdist * zdist) / csize);
  278. if (noiseval < nthresh)
  279. continue;
  280. vm->m_data[i] = n_ore;
  281. }
  282. }
  283. }
  284. ///////////////////////////////////////////////////////////////////////////////
  285. OreVein::OreVein() :
  286. Ore()
  287. {
  288. }
  289. OreVein::~OreVein()
  290. {
  291. delete noise2;
  292. }
  293. void OreVein::generate(MMVManip *vm, int mapseed, u32 blockseed,
  294. v3s16 nmin, v3s16 nmax, u8 *biomemap)
  295. {
  296. PcgRandom pr(blockseed + 520);
  297. MapNode n_ore(c_ore, 0, ore_param2);
  298. int sizex = nmax.X - nmin.X + 1;
  299. int sizey = nmax.Y - nmin.Y + 1;
  300. // Because this ore uses 3D noise the perlinmap Y size can be different in
  301. // different mapchunks due to ore Y limits. So recreate the noise objects
  302. // if Y size has changed.
  303. // Because these noise objects are created multiple times for this ore type
  304. // it is necessary to 'delete' them here.
  305. if (!noise || sizey != sizey_prev) {
  306. delete noise;
  307. delete noise2;
  308. int sizez = nmax.Z - nmin.Z + 1;
  309. noise = new Noise(&np, mapseed, sizex, sizey, sizez);
  310. noise2 = new Noise(&np, mapseed + 436, sizex, sizey, sizez);
  311. sizey_prev = sizey;
  312. }
  313. bool noise_generated = false;
  314. size_t index = 0;
  315. for (int z = nmin.Z; z <= nmax.Z; z++)
  316. for (int y = nmin.Y; y <= nmax.Y; y++)
  317. for (int x = nmin.X; x <= nmax.X; x++, index++) {
  318. u32 i = vm->m_area.index(x, y, z);
  319. if (!vm->m_area.contains(i))
  320. continue;
  321. if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
  322. continue;
  323. if (biomemap && !biomes.empty()) {
  324. u32 bmapidx = sizex * (z - nmin.Z) + (x - nmin.X);
  325. std::unordered_set<u8>::const_iterator it = biomes.find(biomemap[bmapidx]);
  326. if (it == biomes.end())
  327. continue;
  328. }
  329. // Same lazy generation optimization as in OreBlob
  330. if (!noise_generated) {
  331. noise_generated = true;
  332. noise->perlinMap3D(nmin.X, nmin.Y, nmin.Z);
  333. noise2->perlinMap3D(nmin.X, nmin.Y, nmin.Z);
  334. }
  335. // randval ranges from -1..1
  336. float randval = (float)pr.next() / (pr.RANDOM_RANGE / 2) - 1.f;
  337. float noiseval = contour(noise->result[index]);
  338. float noiseval2 = contour(noise2->result[index]);
  339. if (noiseval * noiseval2 + randval * random_factor < nthresh)
  340. continue;
  341. vm->m_data[i] = n_ore;
  342. }
  343. }