mg_biome.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. Minetest
  3. Copyright (C) 2014-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
  4. Copyright (C) 2014-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_biome.h"
  18. #include "mg_decoration.h"
  19. #include "emerge.h"
  20. #include "server.h"
  21. #include "nodedef.h"
  22. #include "map.h" //for MMVManip
  23. #include "util/numeric.h"
  24. #include "porting.h"
  25. #include "settings.h"
  26. ///////////////////////////////////////////////////////////////////////////////
  27. BiomeManager::BiomeManager(Server *server) :
  28. ObjDefManager(server, OBJDEF_BIOME)
  29. {
  30. m_server = server;
  31. // Create default biome to be used in case none exist
  32. Biome *b = new Biome;
  33. b->name = "default";
  34. b->flags = 0;
  35. b->depth_top = 0;
  36. b->depth_filler = -MAX_MAP_GENERATION_LIMIT;
  37. b->depth_water_top = 0;
  38. b->depth_riverbed = 0;
  39. b->min_pos = v3s16(-MAX_MAP_GENERATION_LIMIT,
  40. -MAX_MAP_GENERATION_LIMIT, -MAX_MAP_GENERATION_LIMIT);
  41. b->max_pos = v3s16(MAX_MAP_GENERATION_LIMIT,
  42. MAX_MAP_GENERATION_LIMIT, MAX_MAP_GENERATION_LIMIT);
  43. b->heat_point = 0.0;
  44. b->humidity_point = 0.0;
  45. b->vertical_blend = 0;
  46. b->m_nodenames.emplace_back("mapgen_stone");
  47. b->m_nodenames.emplace_back("mapgen_stone");
  48. b->m_nodenames.emplace_back("mapgen_stone");
  49. b->m_nodenames.emplace_back("mapgen_water_source");
  50. b->m_nodenames.emplace_back("mapgen_water_source");
  51. b->m_nodenames.emplace_back("mapgen_river_water_source");
  52. b->m_nodenames.emplace_back("mapgen_stone");
  53. b->m_nodenames.emplace_back("ignore");
  54. b->m_nodenames.emplace_back("ignore");
  55. b->m_nnlistsizes.push_back(1);
  56. b->m_nodenames.emplace_back("ignore");
  57. b->m_nodenames.emplace_back("ignore");
  58. b->m_nodenames.emplace_back("ignore");
  59. m_ndef->pendNodeResolve(b);
  60. add(b);
  61. }
  62. void BiomeManager::clear()
  63. {
  64. EmergeManager *emerge = m_server->getEmergeManager();
  65. // Remove all dangling references in Decorations
  66. DecorationManager *decomgr = emerge->getWritableDecorationManager();
  67. for (size_t i = 0; i != decomgr->getNumObjects(); i++) {
  68. Decoration *deco = (Decoration *)decomgr->getRaw(i);
  69. deco->biomes.clear();
  70. }
  71. // Don't delete the first biome
  72. for (size_t i = 1; i < m_objects.size(); i++)
  73. delete (Biome *)m_objects[i];
  74. m_objects.resize(1);
  75. }
  76. BiomeManager *BiomeManager::clone() const
  77. {
  78. auto mgr = new BiomeManager();
  79. assert(mgr);
  80. ObjDefManager::cloneTo(mgr);
  81. mgr->m_server = m_server;
  82. return mgr;
  83. }
  84. ////////////////////////////////////////////////////////////////////////////////
  85. void BiomeParamsOriginal::readParams(const Settings *settings)
  86. {
  87. settings->getNoiseParams("mg_biome_np_heat", np_heat);
  88. settings->getNoiseParams("mg_biome_np_heat_blend", np_heat_blend);
  89. settings->getNoiseParams("mg_biome_np_humidity", np_humidity);
  90. settings->getNoiseParams("mg_biome_np_humidity_blend", np_humidity_blend);
  91. }
  92. void BiomeParamsOriginal::writeParams(Settings *settings) const
  93. {
  94. settings->setNoiseParams("mg_biome_np_heat", np_heat);
  95. settings->setNoiseParams("mg_biome_np_heat_blend", np_heat_blend);
  96. settings->setNoiseParams("mg_biome_np_humidity", np_humidity);
  97. settings->setNoiseParams("mg_biome_np_humidity_blend", np_humidity_blend);
  98. }
  99. ////////////////////////////////////////////////////////////////////////////////
  100. BiomeGenOriginal::BiomeGenOriginal(BiomeManager *biomemgr,
  101. const BiomeParamsOriginal *params, v3s16 chunksize)
  102. {
  103. m_bmgr = biomemgr;
  104. m_params = params;
  105. m_csize = chunksize;
  106. noise_heat = new Noise(&params->np_heat,
  107. params->seed, m_csize.X, m_csize.Z);
  108. noise_humidity = new Noise(&params->np_humidity,
  109. params->seed, m_csize.X, m_csize.Z);
  110. noise_heat_blend = new Noise(&params->np_heat_blend,
  111. params->seed, m_csize.X, m_csize.Z);
  112. noise_humidity_blend = new Noise(&params->np_humidity_blend,
  113. params->seed, m_csize.X, m_csize.Z);
  114. heatmap = noise_heat->result;
  115. humidmap = noise_humidity->result;
  116. biomemap = new biome_t[m_csize.X * m_csize.Z];
  117. // Initialise with the ID of 'BIOME_NONE' so that cavegen can get the
  118. // fallback biome when biome generation (which calculates the biomemap IDs)
  119. // is disabled.
  120. memset(biomemap, 0, sizeof(biome_t) * m_csize.X * m_csize.Z);
  121. // Calculating the bounding position of each biome so we know when we might switch
  122. // First gathering all heights where we might switch
  123. std::vector<s16> temp_transition_heights;
  124. temp_transition_heights.reserve(m_bmgr->getNumObjects() * 2);
  125. for (size_t i = 0; i < m_bmgr->getNumObjects(); i++) {
  126. Biome *b = (Biome *)m_bmgr->getRaw(i);
  127. temp_transition_heights.push_back(b->max_pos.Y);
  128. temp_transition_heights.push_back(b->min_pos.Y);
  129. }
  130. // Sorting the biome transition points
  131. std::sort(temp_transition_heights.begin(), temp_transition_heights.end(), std::greater<int>());
  132. // Getting rid of duplicate biome transition points
  133. s16 last = temp_transition_heights[0];
  134. size_t out_pos = 1;
  135. for (size_t i = 1; i < temp_transition_heights.size(); i++){
  136. if (temp_transition_heights[i] != last) {
  137. last = temp_transition_heights[i];
  138. temp_transition_heights[out_pos++] = last;
  139. }
  140. }
  141. biome_transitions = new s16[out_pos];
  142. memcpy(biome_transitions, temp_transition_heights.data(), sizeof(s16) * out_pos);
  143. }
  144. BiomeGenOriginal::~BiomeGenOriginal()
  145. {
  146. delete []biomemap;
  147. delete []biome_transitions;
  148. delete noise_heat;
  149. delete noise_humidity;
  150. delete noise_heat_blend;
  151. delete noise_humidity_blend;
  152. }
  153. s16* BiomeGenOriginal::getBiomeTransitions() const
  154. {
  155. return biome_transitions;
  156. }
  157. BiomeGen *BiomeGenOriginal::clone(BiomeManager *biomemgr) const
  158. {
  159. return new BiomeGenOriginal(biomemgr, m_params, m_csize);
  160. }
  161. float BiomeGenOriginal::calcHeatAtPoint(v3s16 pos) const
  162. {
  163. return NoisePerlin2D(&m_params->np_heat, pos.X, pos.Z, m_params->seed) +
  164. NoisePerlin2D(&m_params->np_heat_blend, pos.X, pos.Z, m_params->seed);
  165. }
  166. float BiomeGenOriginal::calcHumidityAtPoint(v3s16 pos) const
  167. {
  168. return NoisePerlin2D(&m_params->np_humidity, pos.X, pos.Z, m_params->seed) +
  169. NoisePerlin2D(&m_params->np_humidity_blend, pos.X, pos.Z, m_params->seed);
  170. }
  171. Biome *BiomeGenOriginal::calcBiomeAtPoint(v3s16 pos) const
  172. {
  173. return calcBiomeFromNoise(calcHeatAtPoint(pos), calcHumidityAtPoint(pos), pos);
  174. }
  175. void BiomeGenOriginal::calcBiomeNoise(v3s16 pmin)
  176. {
  177. m_pmin = pmin;
  178. noise_heat->perlinMap2D(pmin.X, pmin.Z);
  179. noise_humidity->perlinMap2D(pmin.X, pmin.Z);
  180. noise_heat_blend->perlinMap2D(pmin.X, pmin.Z);
  181. noise_humidity_blend->perlinMap2D(pmin.X, pmin.Z);
  182. for (s32 i = 0; i < m_csize.X * m_csize.Z; i++) {
  183. noise_heat->result[i] += noise_heat_blend->result[i];
  184. noise_humidity->result[i] += noise_humidity_blend->result[i];
  185. }
  186. }
  187. biome_t *BiomeGenOriginal::getBiomes(s16 *heightmap, v3s16 pmin)
  188. {
  189. for (s16 zr = 0; zr < m_csize.Z; zr++)
  190. for (s16 xr = 0; xr < m_csize.X; xr++) {
  191. s32 i = zr * m_csize.X + xr;
  192. Biome *biome = calcBiomeFromNoise(
  193. noise_heat->result[i],
  194. noise_humidity->result[i],
  195. v3s16(pmin.X + xr, heightmap[i], pmin.Z + zr));
  196. biomemap[i] = biome->index;
  197. }
  198. return biomemap;
  199. }
  200. Biome *BiomeGenOriginal::getBiomeAtPoint(v3s16 pos) const
  201. {
  202. return getBiomeAtIndex(
  203. (pos.Z - m_pmin.Z) * m_csize.X + (pos.X - m_pmin.X),
  204. pos);
  205. }
  206. Biome *BiomeGenOriginal::getBiomeAtIndex(size_t index, v3s16 pos) const
  207. {
  208. return calcBiomeFromNoise(
  209. noise_heat->result[index],
  210. noise_humidity->result[index],
  211. pos);
  212. }
  213. Biome *BiomeGenOriginal::calcBiomeFromNoise(float heat, float humidity, v3s16 pos) const
  214. {
  215. Biome *biome_closest = nullptr;
  216. Biome *biome_closest_blend = nullptr;
  217. float dist_min = FLT_MAX;
  218. float dist_min_blend = FLT_MAX;
  219. for (size_t i = 1; i < m_bmgr->getNumObjects(); i++) {
  220. Biome *b = (Biome *)m_bmgr->getRaw(i);
  221. if (!b ||
  222. pos.Y < b->min_pos.Y || pos.Y > b->max_pos.Y + b->vertical_blend ||
  223. pos.X < b->min_pos.X || pos.X > b->max_pos.X ||
  224. pos.Z < b->min_pos.Z || pos.Z > b->max_pos.Z)
  225. continue;
  226. float d_heat = heat - b->heat_point;
  227. float d_humidity = humidity - b->humidity_point;
  228. float dist = (d_heat * d_heat) + (d_humidity * d_humidity);
  229. if (pos.Y <= b->max_pos.Y) { // Within y limits of biome b
  230. if (dist < dist_min) {
  231. dist_min = dist;
  232. biome_closest = b;
  233. }
  234. } else if (dist < dist_min_blend) { // Blend area above biome b
  235. dist_min_blend = dist;
  236. biome_closest_blend = b;
  237. }
  238. }
  239. // Carefully tune pseudorandom seed variation to avoid single node dither
  240. // and create larger scale blending patterns similar to horizontal biome
  241. // blend.
  242. // The calculation can be a negative floating point number, which is an
  243. // undefined behavior if assigned to unsigned integer. Cast the result
  244. // into signed integer before it is casted into unsigned integer to
  245. // eliminate the undefined behavior.
  246. const u64 seed = static_cast<s64>(pos.Y + (heat + humidity) * 0.9f);
  247. PcgRandom rng(seed);
  248. if (biome_closest_blend && dist_min_blend <= dist_min &&
  249. rng.range(0, biome_closest_blend->vertical_blend) >=
  250. pos.Y - biome_closest_blend->max_pos.Y)
  251. return biome_closest_blend;
  252. return (biome_closest) ? biome_closest : (Biome *)m_bmgr->getRaw(BIOME_NONE);
  253. }
  254. ////////////////////////////////////////////////////////////////////////////////
  255. ObjDef *Biome::clone() const
  256. {
  257. auto obj = new Biome();
  258. ObjDef::cloneTo(obj);
  259. NodeResolver::cloneTo(obj);
  260. obj->flags = flags;
  261. obj->c_top = c_top;
  262. obj->c_filler = c_filler;
  263. obj->c_stone = c_stone;
  264. obj->c_water_top = c_water_top;
  265. obj->c_water = c_water;
  266. obj->c_river_water = c_river_water;
  267. obj->c_riverbed = c_riverbed;
  268. obj->c_dust = c_dust;
  269. obj->c_cave_liquid = c_cave_liquid;
  270. obj->c_dungeon = c_dungeon;
  271. obj->c_dungeon_alt = c_dungeon_alt;
  272. obj->c_dungeon_stair = c_dungeon_stair;
  273. obj->depth_top = depth_top;
  274. obj->depth_filler = depth_filler;
  275. obj->depth_water_top = depth_water_top;
  276. obj->depth_riverbed = depth_riverbed;
  277. obj->min_pos = min_pos;
  278. obj->max_pos = max_pos;
  279. obj->heat_point = heat_point;
  280. obj->humidity_point = humidity_point;
  281. obj->vertical_blend = vertical_blend;
  282. return obj;
  283. }
  284. void Biome::resolveNodeNames()
  285. {
  286. getIdFromNrBacklog(&c_top, "mapgen_stone", CONTENT_AIR, false);
  287. getIdFromNrBacklog(&c_filler, "mapgen_stone", CONTENT_AIR, false);
  288. getIdFromNrBacklog(&c_stone, "mapgen_stone", CONTENT_AIR, false);
  289. getIdFromNrBacklog(&c_water_top, "mapgen_water_source", CONTENT_AIR, false);
  290. getIdFromNrBacklog(&c_water, "mapgen_water_source", CONTENT_AIR, false);
  291. getIdFromNrBacklog(&c_river_water, "mapgen_river_water_source", CONTENT_AIR, false);
  292. getIdFromNrBacklog(&c_riverbed, "mapgen_stone", CONTENT_AIR, false);
  293. getIdFromNrBacklog(&c_dust, "ignore", CONTENT_IGNORE, false);
  294. getIdsFromNrBacklog(&c_cave_liquid);
  295. getIdFromNrBacklog(&c_dungeon, "ignore", CONTENT_IGNORE, false);
  296. getIdFromNrBacklog(&c_dungeon_alt, "ignore", CONTENT_IGNORE, false);
  297. getIdFromNrBacklog(&c_dungeon_stair, "ignore", CONTENT_IGNORE, false);
  298. }