mapgen.lua 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. nethermapgen = {}
  2. nethermapgen.modpath = minetest.get_modpath("nethermapgen")
  3. nethermapgen.firetree_modpath = minetest.get_modpath("firetree")
  4. nethermapgen.redshroom_modpath = minetest.get_modpath("redshroom")
  5. -- These are copied in the init script, they MUST match.
  6. nethermapgen.NETHER_START = -25000
  7. nethermapgen.BRIMSTONE_OCEAN = -30800
  8. nethermapgen.BEDROCK_DEPTH = -30900
  9. dofile(nethermapgen.modpath .. "/noise.lua")
  10. dofile(nethermapgen.modpath .. "/functions.lua")
  11. local set_node = minetest.set_node
  12. local get_node = minetest.get_node
  13. local swap_node = minetest.swap_node
  14. local ipairs = ipairs
  15. local math_random = math.random
  16. -- Content IDs used with the voxel manipulator.
  17. local c_air = minetest.get_content_id("air")
  18. local c_ignore = minetest.get_content_id("ignore")
  19. local c_stone = minetest.get_content_id("default:stone")
  20. -- These 2 types are placed at and below the level of the brimstone ocean.
  21. -- They disallow the C++ cavegen from running.
  22. local c_redrack = minetest.get_content_id("rackstone:redrack")
  23. local c_rackstone = minetest.get_content_id("rackstone:rackstone")
  24. -- These 2 types are placed above the brimstone ocean.
  25. -- The C++ cavegen is allowed to run in these nodes.
  26. local c_mgredrack = minetest.get_content_id("rackstone:mg_redrack")
  27. local c_mgrackstone = minetest.get_content_id("rackstone:mg_rackstone")
  28. local c_whitestone = minetest.get_content_id("whitestone:stone")
  29. local c_mossycobble = minetest.get_content_id("default:mossycobble")
  30. local c_cobble = minetest.get_content_id("default:cobble")
  31. local c_netherbrick = minetest.get_content_id("rackstone:brick")
  32. local c_cobblestair = minetest.get_content_id("stairs:stair_cobble")
  33. local c_netherstair = minetest.get_content_id("stairs:stair_rackstone_brick")
  34. local c_water = minetest.get_content_id("default:water_source")
  35. local c_waterflow = minetest.get_content_id("default:water_flowing")
  36. local c_lava = minetest.get_content_id("default:lava_source")
  37. local c_nlava = minetest.get_content_id("lbrim:lava_source")
  38. local c_lavaflow = minetest.get_content_id("default:lava_flowing")
  39. local c_obsidian = minetest.get_content_id("default:obsidian")
  40. local c_vine = minetest.get_content_id("nethervine:vine")
  41. local c_bedrock = minetest.get_content_id("bedrock:bedrock")
  42. -- Externally located tables for performance.
  43. local data = {}
  44. local noisemap1 = {}
  45. local noisemap1_full = {}
  46. local noisemap2 = {}
  47. local noisemap3 = {}
  48. local noisemap3_full = {}
  49. local noisemap4 = {}
  50. local noisemap5 = {}
  51. local noisemap5_full = {}
  52. --[[
  53. Notes on mapgen function. IMPORTANT!
  54. The code loops through all positions in the mapchunk being generated *twice*, once to generate the nether,
  55. and the second time to repair problems at chunk borders caused by caves overgenerating in the C++ mapgen.
  56. These two loops work together, and must be understood together, since the loop which overgenerates can touch
  57. chunks previously generated by the first 'normal' loop.
  58. This 'hack' would not be necessary if we were using Singlenode for the C++ mapgen.
  59. However, we're using Valleys, so the Lua mapgen must work nicely with it.
  60. --]]
  61. nethermapgen.generate_realm = function(vm, minp, maxp, seed)
  62. local nstart = nethermapgen.NETHER_START
  63. local bstart = nethermapgen.BRIMSTONE_OCEAN
  64. local rstart = nethermapgen.BEDROCK_DEPTH
  65. local gennotify_data = {
  66. minp = minp,
  67. maxp = maxp,
  68. }
  69. -- Don't run for out-of-bounds mapchunks.
  70. -- This code makes nethermapgen run for ALL chunks from start, to bottom of world.
  71. local mindepth = nstart + 100
  72. if minp.y > mindepth and maxp.y > mindepth then return end
  73. -- Grab the voxel manipulator.
  74. local emin, emax = vm:get_emerged_area()
  75. vm:get_data(data) -- Read current map data.
  76. local pr = PseudoRandom(seed + 65)
  77. local x1 = maxp.x
  78. local y1 = maxp.y
  79. local z1 = maxp.z
  80. local x0 = minp.x
  81. local y0 = minp.y
  82. local z0 = minp.z
  83. -- To be used with noisemaps as needed.
  84. local area = VoxelArea:new({MinEdge=emin, MaxEdge=emax})
  85. local area2 = VoxelArea:new({MinEdge={x=x0, y=y0, z=z0}, MaxEdge={x=x1, y=y1, z=z1}})
  86. -- Compute side lengths.
  87. local side_len_x = ((x1-x0)+1)
  88. local side_len_y = ((y1-y0)+1)
  89. local side_len_z = ((z1-z0)+1)
  90. local side_len_x_full = ((emax.x-emin.x)+1)
  91. local side_len_y_full = ((emax.y-emin.y)+1)
  92. local side_len_z_full = ((emax.z-emin.z)+1)
  93. local sides3D = {x=side_len_x, y=side_len_y, z=side_len_z}
  94. local sides3D_full = {x=side_len_x_full, y=side_len_y_full, z=side_len_z_full}
  95. local sides2D = {x=side_len_x, y=side_len_z}
  96. local sides2D_full = {x=side_len_x_full, y=side_len_z_full}
  97. local bp3d = {x=x0, y=y0, z=z0}
  98. local bp3d_full = {x=emin.x, y=emin.y, z=emin.z}
  99. local bp2d = {x=x0, y=z0}
  100. local bp2d_full = {x=emin.x, y=emin.z}
  101. -- Get noisemaps.
  102. local perlin1 = minetest.get_perlin_map(nethermapgen.noise1param2d, sides2D)
  103. perlin1:get_2d_map_flat(bp2d, noisemap1)
  104. local perlin2 = minetest.get_perlin_map(nethermapgen.noise2param2d, sides2D)
  105. perlin2:get_2d_map_flat(bp2d, noisemap2)
  106. local perlin3 = minetest.get_perlin_map(nethermapgen.noise3param2d, sides2D)
  107. perlin3:get_2d_map_flat(bp2d, noisemap3)
  108. local perlin4 = minetest.get_perlin_map(nethermapgen.noise4param2d, sides2D)
  109. perlin4:get_2d_map_flat(bp2d, noisemap4)
  110. -- Not currently used.
  111. --local perlin5 = minetest.get_perlin_map(nethermapgen.noise5param3d, sides3D)
  112. --perlin5:get_3d_map_flat(bp3d, noisemap5)
  113. -- Some noisemaps need a full emin/emax version.
  114. local perlin1_full = minetest.get_perlin_map(nethermapgen.noise1param2d, sides2D_full)
  115. perlin1_full:get_2d_map_flat(bp2d_full, noisemap1_full)
  116. local perlin3_full = minetest.get_perlin_map(nethermapgen.noise3param2d, sides2D_full)
  117. perlin3_full:get_2d_map_flat(bp2d_full, noisemap3_full)
  118. local perlin5_full = minetest.get_perlin_map(nethermapgen.noise5param3d, sides3D_full)
  119. perlin5_full:get_3d_map_flat(bp3d_full, noisemap5_full)
  120. -- Localize commonly used functions.
  121. local floor = math.floor
  122. local ceil = math.ceil
  123. local abs = math.abs
  124. -- Pre-pass: convert stuff from the C++ mapgen to nether nodes.
  125. -- Do NOT modify terrain shape in this pass! (Except for the hack, see hack.)
  126. -- We have to scan through the overgenerated edges because those will contain
  127. -- default nodes as well.
  128. for z = emin.z, emax.z do
  129. for x = emin.x, emax.x do
  130. -- Get index into 2D noise arrays.
  131. local nx = (x-emin.x)
  132. local nz = (z-emin.z)
  133. local ni2 = (side_len_z_full*nz+nx)
  134. ni2 = ni2 + 1 -- Lua arrays start indexing at 1, not 0. Urrrrgh. >:(
  135. local n1 = noisemap1_full[ni2]
  136. -- Calculate the variance at the top of the nether's cavern realm,
  137. -- where it merges with default stone caverns.
  138. local rs_top = ceil(nstart+abs(n1)*64)
  139. local rs_bot = floor(nstart-abs(n1)*64)
  140. for y = emin.y, emax.y do
  141. local vp = area:index(x, y, z)
  142. -- Get the type already generated at this position.
  143. local ip = data[vp]
  144. -- Note: sometimes these will be nil, because of accessing outside the array.
  145. -- (We are scanning through the emin/emax range.)
  146. local iu = data[area:index(x, y+1, z)]
  147. local id = data[area:index(x, y-1, z)]
  148. -- Defines rackstone veins all throughout the nether.
  149. local n5 = noisemap5_full[area:index(x, y, z)]
  150. -- Using mapdata already generated by the C++ mapgen, convert regular nodes to nether types.
  151. if ip == c_stone then
  152. if y >= rs_bot and y <= rs_top then
  153. -- Top of the nether where it meets default caverns.
  154. data[vp] = c_mgrackstone
  155. elseif y < rs_bot then
  156. -- Regular rackstone veins run throughout nether.
  157. if abs(n5) < 0.025 then
  158. data[vp] = c_mgrackstone
  159. else
  160. -- Everything else is redrack.
  161. data[vp] = c_mgredrack
  162. end
  163. end
  164. elseif ip == c_cobble or ip == c_mossycobble then
  165. data[vp] = c_netherbrick
  166. elseif ip == c_cobblestair then
  167. data[vp] = c_netherstair
  168. elseif ip == c_water or ip == c_waterflow then
  169. data[vp] = c_air
  170. elseif ip == c_lava or ip == c_lavaflow then
  171. data[vp] = c_air
  172. end
  173. -- Get rid of ores generated by C++ (we use our own).
  174. -- WARNING: this creates bugs because it captures too many nodes, including our own,
  175. -- from neighboring chunks!
  176. --if ip ~= c_air and ip ~= c_ignore then
  177. -- data[vp] = c_mgrackstone
  178. --end
  179. -- HACK:
  180. -- Get rid of the <BEEP> flat horizontal slabs that appear at chunk top/bot edges
  181. -- whenever emerge threads are more than 1. We have to do this *indiscriminately*,
  182. -- which unfortunately modifies the terrain shape more than is actually necessary.
  183. if ip == c_stone or ip == c_mgredrack or ip == c_redrack or ip == c_mgrackstone or ip == c_rackstone then
  184. if (id == c_air or id == c_ignore) and (iu == c_air or iu == c_ignore) then
  185. data[vp] = c_air
  186. end
  187. end
  188. end
  189. end
  190. end
  191. -- Pass the first. Here, I modify the terrain shape (minp/maxp range only) to
  192. -- generate the nether sea, its ceiling, and the cavern floor directly above.
  193. for z = z0, z1 do
  194. for x = x0, x1 do
  195. -- Get index into 2D noise arrays.
  196. local nx = (x-x0)
  197. local nz = (z-z0)
  198. local ni2 = (side_len_z*nz+nx)
  199. ni2 = ni2 + 1 -- Lua arrays start indexing at 1, not 0. Urrrrgh. >:(
  200. local n1 = noisemap1[ni2]
  201. local n2 = noisemap2[ni2]
  202. local n3 = noisemap3[ni2]
  203. local n4 = noisemap4[ni2]
  204. local lakecel = bstart + 30
  205. local cavernf = bstart + 40
  206. local lakelav = bstart
  207. local lakebed = bstart - 2
  208. local islandi = bstart - 2
  209. if n4 > -0.3 then
  210. if abs(n2) > 0.6 then
  211. islandi = bstart + 5
  212. islandi = islandi + pr:next(0, pr:next(1, 2))
  213. islandi = islandi + floor(n1*4)
  214. -- Create random holes.
  215. if pr:next(1, 100) == 1 then islandi = bstart - 2 end
  216. elseif abs(n2) > 0.5 then
  217. islandi = islandi + pr:next(3, 5)
  218. end
  219. end
  220. lakecel = lakecel - pr:next(0, 1+floor(abs(n3) * 3.5))
  221. lakecel = lakecel + floor(abs(n1) * 6)
  222. -- For whole column:
  223. for y = y0, y1 do
  224. local vp = area:index(x, y, z)
  225. -- Generate the endless nether lava ocean, with islands.
  226. if y <= lakebed or y <= islandi then
  227. -- Fill in map below brimstone ocean & create islands.
  228. -- Important: NOT using mg_redrack here, because I don't want C++
  229. -- caves/dungeons carving through this!
  230. data[vp] = c_redrack
  231. elseif y <= lakelav then
  232. -- Special lava for brimstone ocean.
  233. -- Right around islands.
  234. data[vp] = c_nlava
  235. elseif y <= lakecel then
  236. -- Carve out horizontal cavern above brimstone ocean.
  237. -- Note: we fix the ceiling in a later pass.
  238. data[vp] = c_air
  239. end
  240. end
  241. end
  242. end
  243. -- Pass the second. Generate the non-cave-carvable ceiling above the
  244. -- nether sea. To prevent C++ caves cutting through the nethersea roof, this
  245. -- has to be overgenerated.
  246. for z = emin.z, emax.z do
  247. for x = emin.x, emax.x do
  248. -- Get index into 2D noise arrays.
  249. local nx = (x-emin.x)
  250. local nz = (z-emin.z)
  251. local ni2 = (side_len_z_full*nz+nx)
  252. ni2 = ni2 + 1 -- Lua arrays start indexing at 1, not 0. Urrrrgh. >:(
  253. local n1 = noisemap1_full[ni2]
  254. local n3 = noisemap3_full[ni2]
  255. local lakecel = bstart + 30
  256. local cavernf = bstart + 40
  257. lakecel = lakecel - pr:next(0, 1+floor(abs(n3) * 3.5))
  258. lakecel = lakecel + floor(abs(n1) * 5)
  259. -- For whole column:
  260. for y = emin.y, emax.y do
  261. if y > lakecel and y <= cavernf then
  262. local vp = area:index(x, y, z)
  263. -- Fill in huge ceiling holes created when huge caves
  264. -- intersect with the brimstone ocean realm. This "floor" itself
  265. -- supports a second lava ocean in the cavern layers.
  266. local f1 = lakecel + 1
  267. local f2 = lakecel + 5
  268. if y >= f1 and y <= f2 then
  269. -- Important: NOT using mg_redrack here, because I don't want C++
  270. -- caves/dungeons carving through this!
  271. data[vp] = c_redrack
  272. elseif y > f2 and y <= cavernf then
  273. if data[vp] == c_air then
  274. data[vp] = c_nlava
  275. end
  276. end
  277. end
  278. end
  279. end
  280. end
  281. -- Generate the bedrock layer. This MUST overwrite everything else!
  282. for z = emin.z, emax.z do
  283. for x = emin.x, emax.x do
  284. for y = emin.y, emax.y do
  285. if y <= rstart+pr:next(1,pr:next(2, 3)) then
  286. local vp = area:index(x, y, z)
  287. data[vp] = c_bedrock
  288. end
  289. end
  290. end
  291. end
  292. -- These tables will be filled with positions for decorations,
  293. -- to be placed after the voxel manipulator code finishes.
  294. local chnk_pos_flame = {}
  295. local chnk_pos_crystal = {}
  296. local chnk_pos_tree = {}
  297. local chnk_pos_shroom = {}
  298. local chnk_pos_vine = {}
  299. local chnk_pos_grass = {}
  300. local chnk_pos_flower = {}
  301. local is_netherock = function(ip)
  302. if ip == c_redrack or
  303. ip == c_rackstone or
  304. ip == c_mgredrack or
  305. ip == c_mgrackstone then
  306. return true
  307. else
  308. return false
  309. end
  310. end
  311. -- Final mapgen pass, for finding floors and ceilings.
  312. -- Note: this has to be a seperate pass because otherwise the code
  313. -- will find floors and ceilings where there aren't any.
  314. for x = x0, x1 do
  315. for z = z0, z1 do
  316. for y = y0, y1 do
  317. local vp = area:index(x, y, z)
  318. local vu = area:index(x, y+1, z)
  319. local vd = area:index(x, y-1, z)
  320. local ip = data[vp]
  321. local iu = data[vu]
  322. local id = data[vd]
  323. local tree_chance = 5000
  324. local flower_chance = 400
  325. local vine_chance = 10
  326. local cavernf = bstart + 41
  327. if y >= cavernf and y <= cavernf + 7 then
  328. tree_chance = 70 -- Increase trees.
  329. flower_chance = 200 -- Increase flowers.
  330. vine_chance = 30 -- Reduce vines.
  331. end
  332. -- Found floor.
  333. if is_netherock(ip) and iu == c_air then
  334. if pr:next(0, 2000) == 0 then
  335. chnk_pos_flame[#chnk_pos_flame+1] = {x=x, y=y+1, z=z}
  336. elseif pr:next(0, tree_chance) == 0 then
  337. chnk_pos_tree[#chnk_pos_tree+1] = {x=x, y=y+1, z=z}
  338. elseif pr:next(0, 3000) == 0 then
  339. chnk_pos_shroom[#chnk_pos_shroom+1] = {x=x, y=y+1, z=z}
  340. elseif pr:next(0, 200) == 0 then
  341. chnk_pos_grass[#chnk_pos_grass+1] = {x=x, y=y+1, z=z}
  342. elseif pr:next(0, flower_chance) == 0 and y > -30760 then
  343. chnk_pos_flower[#chnk_pos_flower+1] = {x=x, y=y+1, z=z}
  344. end
  345. end
  346. -- Found roof.
  347. if is_netherock(ip) and id == c_air then
  348. if pr:next(0, 4000) == 0 then
  349. chnk_pos_crystal[#chnk_pos_crystal+1] = {x=x, y=y-1, z=z}
  350. elseif pr:next(0, vine_chance) == 0 then
  351. chnk_pos_vine[#chnk_pos_vine+1] = {x=x, y=y-1, z=z}
  352. end
  353. end
  354. end
  355. end
  356. end
  357. -- Finalize voxel manipulator.
  358. vm:set_data(data)
  359. minetest.generate_ores(vm, minp, maxp)
  360. vm:set_lighting({day=0, night=0})
  361. vm:calc_lighting(emin, emax, true)
  362. vm:update_liquids()
  363. --vm:write_to_map()
  364. for k, v in ipairs(chnk_pos_flame) do
  365. nethermapgen.scatter_flames(v)
  366. end
  367. for k, v in ipairs(chnk_pos_tree) do
  368. local p = table.copy(v)
  369. p.y = p.y - 1
  370. set_node(p, {name="rackstone:dauthsand"})
  371. nethermapgen.create_firetree(vm, {x=p.x, y=p.y+1, z=p.z})
  372. end
  373. for k, v in ipairs(chnk_pos_shroom) do
  374. local p = table.copy(v)
  375. p.y = p.y - 1
  376. set_node(p, {name="rackstone:dauthsand"})
  377. nethermapgen.create_shroom(vm, {x=p.x, y=p.y+1, z=p.z})
  378. end
  379. for k, v in ipairs(chnk_pos_crystal) do
  380. nethermapgen.place_crystal(v)
  381. end
  382. for k, v in ipairs(chnk_pos_vine) do
  383. local p = table.copy(v)
  384. local r = pr:next(2, 7)
  385. for i = 1, r, 1 do
  386. if get_node(p).name ~= "air" then
  387. break
  388. end
  389. set_node(p, {name="nethervine:vine"})
  390. p.y = p.y - 1
  391. end
  392. end
  393. for k, v in ipairs(chnk_pos_grass) do
  394. swap_node(v, {name="nether:grass_" .. math_random(1, 3)})
  395. end
  396. for k, v in ipairs(chnk_pos_flower) do
  397. swap_node(v, {name="nether:glowflower"})
  398. end
  399. minetest.save_gen_notify("nether:mapgen_info", gennotify_data)
  400. end
  401. -- Register the mapgen callback.
  402. minetest.register_on_generated(function(...)
  403. nethermapgen.generate_realm(...)
  404. end)