Fix vines

This commit is contained in:
kay27 2022-01-17 03:25:47 +04:00
parent e528cc7d8b
commit 66fded90d5
7 changed files with 273 additions and 255 deletions

View File

@ -15,19 +15,19 @@ See https://git.minetest.land/MineClone2/MineClone2/issues/1395
`vm_context` will pass into next lvm callback function from the queue! `vm_context` will pass into next lvm callback function from the queue!
`vm_context`: a table which already contains some LVM data as the fields, and some of them can be added in your lvm callback function: `vm_context`: a table which already contains some LVM data as the fields, and some of them can be added in your lvm callback function:
`vm`: curent voxel manipulator object itself; `vm`: curent voxel manipulator object itself;
`blockseed`: seed of this mapchunk; `chunkseed`: seed of this mapchunk;
`minp` & `maxp`: minimum and maximum chunk position; `minp` & `maxp`: minimum and maximum chunk position;
`emin` & `emax`: minimum and maximum chunk position WITH SHELL AROUND IT; `emin` & `emax`: minimum and maximum chunk position WITH SHELL AROUND IT;
`area`: voxel area, can be helpful to access data; `area`: voxel area, can be helpful to access data;
`data`: LVM buffer data array, data loads into it before the callbacks; `data`: LVM buffer data array, data loads into it before the callbacks;
`write`: set it to true in your lvm callback functionm, if you changed `data` and want to write it; `write`: set it to true in your lvm callback functionm, if you changed `data` and want to write it;
`data2`: LVM buffer data array of `param2`, !NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - you load it yourself: `param2_data`: LVM buffer data array of `param2`, !NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - you load it yourself:
`vm_context.data2 = vm_context.data2 or vm_context.vm.get_param2_data(vm_context.lvm_param2_buffer)` `vm_context.param2_data = vm_context.param2_data or vm_context.vm:get_param2_data(vm_context.lvm_param2_buffer)`
`write_param2`: set it to true in your lvm callback function, if you used `data2` and want to write it; `write_param2`: set it to true in your lvm callback function, if you used `param2_data` and want to write it;
`light`: LVM buffer data array of light, !NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - you load it yourself: `light`: LVM buffer data array of light, !NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - you load it yourself:
`vm_context.light = vm_context.light or vm_context.vm.get_light_data(vm_context.lvm_light_buffer)` `vm_context.light = vm_context.light or vm_context.vm.get_light_data(vm_context.lvm_light_buffer)`
`write_light`: set it to true in your lvm callback function, if you used `light` and want to write it; `write_light`: set it to true in your lvm callback function, if you used `light` and want to write it;
`lvm_param2_buffer`: static `param2` buffer pointer, used to load `data2` array; `lvm_param2_buffer`: static `param2` buffer pointer, used to load `param2_data` array;
`shadow`: set it to false to disable shadow propagation; `shadow`: set it to false to disable shadow propagation;
`heightmap`: mapgen object contanting y coordinates of ground level, `heightmap`: mapgen object contanting y coordinates of ground level,
!NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - load it yourself: !NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - load it yourself:

View File

@ -125,7 +125,7 @@ minetest.register_on_shutdown(function()
end) end)
local vm_context -- here will be many references and flags, like: param2, light_data, heightmap, biomemap, heatmap, humiditymap, gennotify, write_lvm, write_param2, shadow local vm_context -- here will be many references and flags, like: param2, light_data, heightmap, biomemap, heatmap, humiditymap, gennotify, write_lvm, write_param2, shadow
local data, data2, light, area local data, param2_data, light, area
local current_blocks = {} local current_blocks = {}
local current_chunks = {} local current_chunks = {}
local lvm_buffer, lvm_param2_buffer, lvm_light_buffer = {}, {}, {} -- Static buffer pointers local lvm_buffer, lvm_param2_buffer, lvm_light_buffer = {}, {}, {} -- Static buffer pointers
@ -139,7 +139,7 @@ minetest.register_on_generated(function(minp, maxp, chunkseed)
area = VoxelArea:new({MinEdge=emin, MaxEdge=emax}) area = VoxelArea:new({MinEdge=emin, MaxEdge=emax})
vm_context = { vm_context = {
data = data, data = data,
data2 = data2, param2_data = param2_data,
light = light, light = light,
area = area, area = area,
lvm_buffer = lvm_buffer, lvm_buffer = lvm_buffer,
@ -270,7 +270,7 @@ minetest.register_on_generated(function(minp, maxp, chunkseed)
vm:set_data(data) vm:set_data(data)
end end
if vm_context.write_param2 then if vm_context.write_param2 then
vm:set_param2_data(data2) vm:set_param2_data(vm_context.param2_data)
end end
if vm_context.write_light then if vm_context.write_light then
vm:set_light_data(light) vm:set_light_data(light)
@ -291,7 +291,7 @@ minetest.register_on_generated(function(minp, maxp, chunkseed)
area = VoxelArea:new({MinEdge=minp, MaxEdge=maxp}) area = VoxelArea:new({MinEdge=minp, MaxEdge=maxp})
vm_context = { vm_context = {
data = data, data = data,
data2 = data2, param2_data = param2_data,
light = light, light = light,
area = area, area = area,
lvm_buffer = lvm_buffer, lvm_buffer = lvm_buffer,
@ -314,7 +314,7 @@ minetest.register_on_generated(function(minp, maxp, chunkseed)
vm:set_data(data) vm:set_data(data)
end end
if vm_context.write_param2 then if vm_context.write_param2 then
vm:set_param2_data(data2) vm:set_param2_data(param2_data)
end end
if vm_context.write_light then if vm_context.write_light then
vm:set_light_data(light) vm:set_light_data(light)

View File

@ -4,7 +4,8 @@
local modpath = minetest.get_modpath(minetest.get_current_modname()) local modpath = minetest.get_modpath(minetest.get_current_modname())
local mg_name = minetest.get_mapgen_setting("mg_name") local mg_name = mcl_mapgen.name
local v6 = mcl_mapgen.v6
local math = math local math = math
local vector = vector local vector = vector
@ -381,7 +382,7 @@ function mcl_core.generate_tree(pos, tree_type, options)
local balloon = options and options.balloon local balloon = options and options.balloon
if tree_type == nil or tree_type == OAK_TREE_ID then if tree_type == nil or tree_type == OAK_TREE_ID then
if mg_name == "v6" then if v6 then
mcl_core.generate_v6_oak_tree(pos) mcl_core.generate_v6_oak_tree(pos)
else else
if balloon then if balloon then
@ -396,7 +397,7 @@ function mcl_core.generate_tree(pos, tree_type, options)
if two_by_two then if two_by_two then
mcl_core.generate_huge_spruce_tree(pos) mcl_core.generate_huge_spruce_tree(pos)
else else
if mg_name == "v6" then if v6 then
mcl_core.generate_v6_spruce_tree(pos) mcl_core.generate_v6_spruce_tree(pos)
else else
mcl_core.generate_spruce_tree(pos) mcl_core.generate_spruce_tree(pos)
@ -408,7 +409,7 @@ function mcl_core.generate_tree(pos, tree_type, options)
if two_by_two then if two_by_two then
mcl_core.generate_huge_jungle_tree(pos) mcl_core.generate_huge_jungle_tree(pos)
else else
if mg_name == "v6" then if v6 then
mcl_core.generate_v6_jungle_tree(pos) mcl_core.generate_v6_jungle_tree(pos)
else else
mcl_core.generate_jungle_tree(pos) mcl_core.generate_jungle_tree(pos)
@ -786,7 +787,7 @@ function mcl_core.generate_huge_jungle_tree(pos)
end end
local grass_spread_randomizer = PseudoRandom(minetest.get_mapgen_setting("seed")) local grass_spread_randomizer = PseudoRandom(mcl_mapgen.seed)
function mcl_core.get_grass_palette_index(pos) function mcl_core.get_grass_palette_index(pos)
local biome_data = minetest.get_biome_data(pos) local biome_data = minetest.get_biome_data(pos)

View File

@ -1,4 +1,4 @@
name = mcl_core name = mcl_core
description = Core items of MineClone 2: Basic biome blocks (dirt, sand, stones, etc.), derived items, glass, sugar cane, cactus, barrier, mining tools, hand, craftitems, and misc. items which don't really fit anywhere else. description = Core items of MineClone 2: Basic biome blocks (dirt, sand, stones, etc.), derived items, glass, sugar cane, cactus, barrier, mining tools, hand, craftitems, and misc. items which don't really fit anywhere else.
depends = mcl_autogroup, mcl_init, mcl_sounds, mcl_particles, mcl_util, mcl_worlds, doc_items, mcl_enchanting, mcl_colors depends = mcl_autogroup, mcl_init, mcl_sounds, mcl_particles, mcl_util, mcl_worlds, doc_items, mcl_enchanting, mcl_colors, mcl_mapgen
optional_depends = doc optional_depends = doc

View File

@ -84,21 +84,9 @@ local c_realm_barrier = minetest.get_content_id("mcl_core:realm_barrier")
local c_top_snow = minetest.get_content_id("mcl_core:snow") local c_top_snow = minetest.get_content_id("mcl_core:snow")
local c_snow_block = minetest.get_content_id("mcl_core:snowblock") local c_snow_block = minetest.get_content_id("mcl_core:snowblock")
local c_clay = minetest.get_content_id("mcl_core:clay") local c_clay = minetest.get_content_id("mcl_core:clay")
local c_leaves = minetest.get_content_id("mcl_core:leaves")
local c_jungleleaves = minetest.get_content_id("mcl_core:jungleleaves")
--local c_jungletree = minetest.get_content_id("mcl_core:jungletree") --local c_jungletree = minetest.get_content_id("mcl_core:jungletree")
local c_vine = minetest.get_content_id("mcl_core:vine")
local c_air = minetest.CONTENT_AIR local c_air = minetest.CONTENT_AIR
local c_cocoas = nil
if minetest.get_modpath("mcl_cocoas") then
c_cocoas = {
minetest.get_content_id("mcl_cocoas:cocoa_1"),
minetest.get_content_id("mcl_cocoas:cocoa_2"),
minetest.get_content_id("mcl_cocoas:cocoa_3")
}
end
-- --
-- Ore generation -- Ore generation
-- --
@ -1167,9 +1155,6 @@ minetest.set_mapgen_setting("mg_flags", mg_flags_str, true)
return x, z return x, z
end]] end]]
-- Perlin noise objects
local perlin_vines, perlin_vines_fine, perlin_vines_upwards, perlin_vines_length, perlin_vines_density
local dragon_spawn_pos = false local dragon_spawn_pos = false
local dragon_spawned, portal_generated = false, false local dragon_spawned, portal_generated = false, false
@ -1209,214 +1194,6 @@ function mcl_mapgen_core.generate_end_exit_portal(pos)
portal_generated = true portal_generated = true
end end
-- Buffers for LuaVoxelManip
-- local lvm_buffer = {}
-- local lvm_buffer_param2 = {}
-- Generate tree decorations in the bounding box. This adds:
-- * Cocoa at jungle trees
-- * Jungle tree vines
-- * Oak vines in swamplands
local function generate_tree_decorations(minp, maxp, seed, data, param2_data, area, biomemap, lvm_used, pr)
if maxp.y < 0 then
return lvm_used
end
local oaktree, oakleaves, jungletree, jungleleaves = {}, {}, {}, {}
local swampland = minetest.get_biome_id("Swampland")
local swampland_shore = minetest.get_biome_id("Swampland_shore")
local jungle = minetest.get_biome_id("Jungle")
local jungle_shore = minetest.get_biome_id("Jungle_shore")
local jungle_m = minetest.get_biome_id("JungleM")
local jungle_m_shore = minetest.get_biome_id("JungleM_shore")
local jungle_edge = minetest.get_biome_id("JungleEdge")
local jungle_edge_shore = minetest.get_biome_id("JungleEdge_shore")
local jungle_edge_m = minetest.get_biome_id("JungleEdgeM")
local jungle_edge_m_shore = minetest.get_biome_id("JungleEdgeM_shore")
-- Modifier for Jungle M biome: More vines and cocoas
local dense_vegetation = false
if biomemap then
-- Biome map available: Check if the required biome (jungle or swampland)
-- is in this mapchunk. We are only interested in trees in the correct biome.
-- The nodes are added if the correct biome is *anywhere* in the mapchunk.
-- TODO: Strictly generate vines in the correct biomes only.
local swamp_biome_found, jungle_biome_found = false, false
for b=1, #biomemap do
local id = biomemap[b]
if not swamp_biome_found and (id == swampland or id == swampland_shore) then
oaktree = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:tree"})
oakleaves = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:leaves"})
swamp_biome_found = true
end
if not jungle_biome_found and (id == jungle or id == jungle_shore or id == jungle_m or id == jungle_m_shore or id == jungle_edge or id == jungle_edge_shore or id == jungle_edge_m or id == jungle_edge_m_shore) then
jungletree = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:jungletree"})
jungleleaves = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:jungleleaves"})
jungle_biome_found = true
end
if not dense_vegetation and (id == jungle_m or id == jungle_m_shore) then
dense_vegetation = true
end
if swamp_biome_found and jungle_biome_found and dense_vegetation then
break
end
end
else
-- If there is no biome map, we just count all jungle things we can find.
-- Oak vines will not be generated.
jungletree = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:jungletree"})
jungleleaves = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:jungleleaves"})
end
local pos, treepos, dir
if c_cocoas ~= nil then
local cocoachance = 40
if dense_vegetation then
cocoachance = 32
end
-- Pass 1: Generate cocoas at jungle trees
for n = 1, #jungletree do
pos = table.copy(jungletree[n])
treepos = table.copy(pos)
if minetest.find_node_near(pos, 1, {"mcl_core:jungleleaves"}) then
dir = pr:next(1, cocoachance)
if dir == 1 then
pos.z = pos.z + 1
elseif dir == 2 then
pos.z = pos.z - 1
elseif dir == 3 then
pos.x = pos.x + 1
elseif dir == 4 then
pos.x = pos.x -1
end
local p_pos = area:index(pos.x, pos.y, pos.z)
local l = minetest.get_node_light(pos)
if dir < 5
and data[p_pos] == c_air
and l and l > 12 then
local c = pr:next(1, 3)
data[p_pos] = c_cocoas[c]
param2_data[p_pos] = minetest.dir_to_facedir(vector.subtract(treepos, pos))
lvm_used = true
end
end
end
end
-- Pass 2: Generate vines at jungle wood, jungle leaves in jungle and oak wood, oak leaves in swampland
perlin_vines = perlin_vines or minetest.get_perlin(555, 4, 0.6, 500)
perlin_vines_fine = perlin_vines_fine or minetest.get_perlin(43000, 3, 0.6, 1)
perlin_vines_length = perlin_vines_length or minetest.get_perlin(435, 4, 0.6, 75)
perlin_vines_upwards = perlin_vines_upwards or minetest.get_perlin(436, 3, 0.6, 10)
perlin_vines_density = perlin_vines_density or minetest.get_perlin(436, 3, 0.6, 500)
-- Extra long vines in Jungle M
local maxvinelength = 7
if dense_vegetation then
maxvinelength = 14
end
local treething
for i=1, 4 do
if i==1 then
treething = jungletree
elseif i == 2 then
treething = jungleleaves
elseif i == 3 then
treething = oaktree
elseif i == 4 then
treething = oakleaves
end
for n = 1, #treething do
pos = treething[n]
treepos = table.copy(pos)
local dirs = {
{x=1,y=0,z=0},
{x=-1,y=0,z=0},
{x=0,y=0,z=1},
{x=0,y=0,z=-1},
}
for d = 1, #dirs do
local pos = vector.add(pos, dirs[d])
local p_pos = area:index(pos.x, pos.y, pos.z)
local vine_threshold = math.max(0.33333, perlin_vines_density:get_2d(pos))
if dense_vegetation then
vine_threshold = vine_threshold * (2/3)
end
if perlin_vines:get_2d(pos) > -1.0 and perlin_vines_fine:get_3d(pos) > vine_threshold and data[p_pos] == c_air then
local rdir = {}
rdir.x = -dirs[d].x
rdir.y = dirs[d].y
rdir.z = -dirs[d].z
local param2 = minetest.dir_to_wallmounted(rdir)
-- Determine growth direction
local grow_upwards = false
-- Only possible on the wood, not on the leaves
if i == 1 then
grow_upwards = perlin_vines_upwards:get_3d(pos) > 0.8
end
if grow_upwards then
-- Grow vines up 1-4 nodes, even through jungleleaves.
-- This may give climbing access all the way to the top of the tree :-)
-- But this will be fairly rare.
local length = math.ceil(math.abs(perlin_vines_length:get_3d(pos)) * 4)
for l=0, length-1 do
local t_pos = area:index(treepos.x, treepos.y, treepos.z)
if (data[p_pos] == c_air or data[p_pos] == c_jungleleaves or data[p_pos] == c_leaves) and mcl_core.supports_vines(minetest.get_name_from_content_id(data[t_pos])) then
data[p_pos] = c_vine
param2_data[p_pos] = param2
lvm_used = true
else
break
end
pos.y = pos.y + 1
p_pos = area:index(pos.x, pos.y, pos.z)
treepos.y = treepos.y + 1
end
else
-- Grow vines down, length between 1 and maxvinelength
local length = math.ceil(math.abs(perlin_vines_length:get_3d(pos)) * maxvinelength)
for l=0, length-1 do
if data[p_pos] == c_air then
data[p_pos] = c_vine
param2_data[p_pos] = param2
lvm_used = true
else
break
end
pos.y = pos.y - 1
p_pos = area:index(pos.x, pos.y, pos.z)
end
end
end
end
end
end
return lvm_used
end
-- Generate mushrooms in caves manually. -- Generate mushrooms in caves manually.
-- Minetest's API does not support decorations in caves yet. :-( -- Minetest's API does not support decorations in caves yet. :-(
local function generate_underground_mushrooms(minp, maxp, seed) local function generate_underground_mushrooms(minp, maxp, seed)
@ -1604,8 +1381,8 @@ end
-- Below the bedrock, generate air/void -- Below the bedrock, generate air/void
local function basic_safe(vm_context) local function basic_safe(vm_context)
local vm, data, emin, emax, area, minp, maxp, chunkseed, blockseed = vm_context.vm, vm_context.data, vm_context.emin, vm_context.emax, vm_context.area, vm_context.minp, vm_context.maxp, vm_context.chunkseed, vm_context.blockseed local vm, data, emin, emax, area, minp, maxp, chunkseed, blockseed = vm_context.vm, vm_context.data, vm_context.emin, vm_context.emax, vm_context.area, vm_context.minp, vm_context.maxp, vm_context.chunkseed, vm_context.blockseed
vm_context.data2 = vm_context.data2 or vm:get_param2_data(vm_context.lvm_param2_buffer) vm_context.param2_data = vm_context.param2_data or vm:get_param2_data(vm_context.lvm_param2_buffer)
local data2 = vm_context.data2 local param2_data = vm_context.param2_data
local lvm_used = false local lvm_used = false
local pr = PseudoRandom(blockseed) local pr = PseudoRandom(blockseed)
@ -1649,14 +1426,9 @@ local function basic_safe(vm_context)
end end
end end
-- Clay, vines, cocoas
-- lvm_used = generate_clay(minp, maxp, chunkseed, data, area, lvm_used)
vm_context.biomemap = vm_context.biomemap or minetest.get_mapgen_object("biomemap") vm_context.biomemap = vm_context.biomemap or minetest.get_mapgen_object("biomemap")
local biomemap = vm_context.biomemap local biomemap = vm_context.biomemap
lvm_used = generate_tree_decorations(minp, maxp, blockseed, data, data2, area, biomemap, lvm_used, pr)
----- Interactive block fixing section ----- ----- Interactive block fixing section -----
----- The section to perform basic block overrides of the core mapgen generated world. ----- ----- The section to perform basic block overrides of the core mapgen generated world. -----
@ -1714,8 +1486,8 @@ local function basic_safe(vm_context)
if bn then if bn then
local biome = minetest.registered_biomes[bn] local biome = minetest.registered_biomes[bn]
if biome and biome._mcl_biome_type then if biome and biome._mcl_biome_type then
data2[p_pos] = biome._mcl_palette_index param2_data[p_pos] = biome._mcl_palette_index
lvm_used = true vm_context.write_param2 = true
end end
end end
if data[p_pos] == c_dirt_with_grass_snow and p_pos_above and data[p_pos_above] ~= c_top_snow and data[p_pos_above] ~= c_snow_block then if data[p_pos] == c_dirt_with_grass_snow and p_pos_above and data[p_pos_above] ~= c_top_snow and data[p_pos_above] ~= c_snow_block then
@ -1829,6 +1601,7 @@ mcl_mapgen.register_mapgen_block_lvm(basic_safe, 1)
local modpath = minetest.get_modpath(minetest.get_current_modname()) local modpath = minetest.get_modpath(minetest.get_current_modname())
dofile(modpath .. "/clay.lua") dofile(modpath .. "/clay.lua")
dofile(modpath .. "/tree_decoration.lua")
if minetest.get_modpath("mcl_structures") then if minetest.get_modpath("mcl_structures") then
dofile(modpath .. "/structures.lua") dofile(modpath .. "/structures.lua")
end end

View File

@ -163,16 +163,9 @@ local function spawn_witch_hut(p, nn, pr, vm_context)
vm_context.biomemap = minetest_get_mapgen_object('biomemap') vm_context.biomemap = minetest_get_mapgen_object('biomemap')
biomemap = vm_context.biomemap biomemap = vm_context.biomemap
end end
-- minetest.chat_send_all(minetest.serialize(biomemap))
local swampland = minetest.get_biome_id("Swampland") local swampland = minetest.get_biome_id("Swampland")
local swampland_shore = minetest.get_biome_id("Swampland_shore") local swampland_shore = minetest.get_biome_id("Swampland_shore")
local bi = xz_to_biomemap_index(p.x, p.z, vm_context.minp, vm_context.maxp) local bi = xz_to_biomemap_index(p.x, p.z, vm_context.minp, vm_context.maxp)
if (biomemap[bi] == swampland) then
minetest.chat_send_all('swampland')
end
if (biomemap[bi] == swampland_shore) then
minetest.chat_send_all('swampland_shore')
end
-- if biomemap[bi] ~= swampland and biomemap[bi] ~= swampland_shore then return end -- if biomemap[bi] ~= swampland and biomemap[bi] ~= swampland_shore then return end
end end

View File

@ -0,0 +1,251 @@
-- Generate tree decorations in the bounding box. This adds:
-- * Cocoa at jungle trees
-- * Jungle tree vines
-- * Oak vines in swamplands
local minetest_find_nodes_in_area = minetest.find_nodes_in_area
local minetest_find_node_near = minetest.find_node_near
local minetest_get_node_light = minetest.get_node_light
local minetest_dir_to_facedir = minetest.dir_to_facedir
local minetest_dir_to_wallmounted = minetest.dir_to_wallmounted
local table_copy = table.copy
local vector_subtract = vector.subtract
local vector_add = vector.add
local math_max = math.max
local math_ceil = math.ceil
local math_abs = math.abs
local c_air = minetest.CONTENT_AIR
local c_cocoas
local c_jungleleaves = minetest.get_content_id("mcl_core:jungleleaves")
local c_leaves = minetest.get_content_id("mcl_core:leaves")
local c_vine = minetest.get_content_id("mcl_core:vine")
if minetest.get_modpath("mcl_cocoas") then
c_cocoas = {
minetest.get_content_id("mcl_cocoas:cocoa_1"),
minetest.get_content_id("mcl_cocoas:cocoa_2"),
minetest.get_content_id("mcl_cocoas:cocoa_3"),
}
end
local swampland
local swampland_shore
local jungle
local jungle_shore
local jungle_m
local jungle_m_shore
local jungle_edge
local jungle_edge_shore
local jungle_edge_m
local jungle_edge_m_shore
local perlin_vines, perlin_vines_fine, perlin_vines_upwards, perlin_vines_length, perlin_vines_density
local dirs = {
{x = 1, y = 0, z = 0},
{x = -1, y = 0, z = 0},
{x = 0, y = 0, z = 1},
{x = 0, y = 0, z = -1},
}
local function generate_tree_decorations(vm_context)
local maxp = vm_context.maxp
if maxp.y < 0 then return end
local minp = vm_context.minp
local data = vm_context.data
vm_context.param2_data = vm_context.param2_data or vm_context.vm:get_param2_data(vm_context.lvm_param2_buffer)
local param2_data = vm_context.param2_data
local area = vm_context.area
local biomemap = vm_context.biomemap
local pr = PseudoRandom(vm_context.chunkseed)
local oaktree, oakleaves, jungletree, jungleleaves = {}, {}, {}, {}
-- Modifier for Jungle M biome: More vines and cocoas
local dense_vegetation = false
if biomemap then
swampland = swampland or minetest.get_biome_id("Swampland")
swampland_shore = swampland_shore or minetest.get_biome_id("Swampland_shore")
jungle = jungle or minetest.get_biome_id("Jungle")
jungle_shore = jungle_shore or minetest.get_biome_id("Jungle_shore")
jungle_m = jungle_m or minetest.get_biome_id("JungleM")
jungle_m_shore = jungle_m_shore or minetest.get_biome_id("JungleM_shore")
jungle_edge = jungle_edge or minetest.get_biome_id("JungleEdge")
jungle_edge_shore = jungle_edge_shore or minetest.get_biome_id("JungleEdge_shore")
jungle_edge_m = jungle_edge_m or minetest.get_biome_id("JungleEdgeM")
jungle_edge_m_shore = jungle_edge_m_shore or minetest.get_biome_id("JungleEdgeM_shore")
-- Biome map available: Check if the required biome (jungle or swampland)
-- is in this mapchunk. We are only interested in trees in the correct biome.
-- The nodes are added if the correct biome is *anywhere* in the mapchunk.
-- TODO: Strictly generate vines in the correct biomes only.
local swamp_biome_found, jungle_biome_found = false, false
for b=1, #biomemap do
local id = biomemap[b]
if not swamp_biome_found and (id == swampland or id == swampland_shore) then
oaktree = minetest_find_nodes_in_area(minp, maxp, {"mcl_core:tree"})
oakleaves = minetest_find_nodes_in_area(minp, maxp, {"mcl_core:leaves"})
swamp_biome_found = true
end
if not jungle_biome_found and (id == jungle or id == jungle_shore or id == jungle_m or id == jungle_m_shore or id == jungle_edge or id == jungle_edge_shore or id == jungle_edge_m or id == jungle_edge_m_shore) then
jungletree = minetest_find_nodes_in_area(minp, maxp, {"mcl_core:jungletree"})
jungleleaves = minetest_find_nodes_in_area(minp, maxp, {"mcl_core:jungleleaves"})
jungle_biome_found = true
end
if not dense_vegetation and (id == jungle_m or id == jungle_m_shore) then
dense_vegetation = true
end
if swamp_biome_found and jungle_biome_found and dense_vegetation then
break
end
end
else
-- If there is no biome map, we just count all jungle things we can find.
-- Oak vines will not be generated.
jungletree = minetest_find_nodes_in_area(minp, maxp, {"mcl_core:jungletree"})
jungleleaves = minetest_find_nodes_in_area(minp, maxp, {"mcl_core:jungleleaves"})
end
local pos, treepos, dir
if c_cocoas then
local cocoachance = 40
if dense_vegetation then
cocoachance = 32
end
-- Pass 1: Generate cocoas at jungle trees
for n = 1, #jungletree do
pos = table_copy(jungletree[n])
treepos = table_copy(pos)
if minetest_find_node_near(pos, 1, {"mcl_core:jungleleaves"}) then
dir = pr:next(1, cocoachance)
if dir == 1 then
pos.z = pos.z + 1
elseif dir == 2 then
pos.z = pos.z - 1
elseif dir == 3 then
pos.x = pos.x + 1
elseif dir == 4 then
pos.x = pos.x -1
end
local p_pos = area:index(pos.x, pos.y, pos.z)
local l = minetest_get_node_light(pos)
if dir < 5
and data[p_pos] == c_air
and l and l > 12 then
local c = pr:next(1, 3)
data[p_pos] = c_cocoas[c]
vm_context.write = true
param2_data[p_pos] = minetest_dir_to_facedir(vector_subtract(treepos, pos))
vm_context.write_param2 = true
end
end
end
end
-- Pass 2: Generate vines at jungle wood, jungle leaves in jungle and oak wood, oak leaves in swampland
perlin_vines = perlin_vines or minetest.get_perlin(555, 4, 0.6, 500)
perlin_vines_fine = perlin_vines_fine or minetest.get_perlin(43000, 3, 0.6, 1)
perlin_vines_length = perlin_vines_length or minetest.get_perlin(435, 4, 0.6, 75)
perlin_vines_upwards = perlin_vines_upwards or minetest.get_perlin(436, 3, 0.6, 10)
perlin_vines_density = perlin_vines_density or minetest.get_perlin(436, 3, 0.6, 500)
-- Extra long vines in Jungle M
local maxvinelength = 7
if dense_vegetation then
maxvinelength = 14
end
local treething
for i=1, 4 do
if i==1 then
treething = jungletree
elseif i == 2 then
treething = jungleleaves
elseif i == 3 then
treething = oaktree
elseif i == 4 then
treething = oakleaves
end
for n = 1, #treething do
pos = treething[n]
treepos = table_copy(pos)
for d = 1, #dirs do
local pos = vector_add(pos, dirs[d])
local p_pos = area:index(pos.x, pos.y, pos.z)
local vine_threshold = math_max(0.33333, perlin_vines_density:get_2d(pos))
if dense_vegetation then
vine_threshold = vine_threshold * (2/3)
end
if perlin_vines:get_2d(pos) > -1.0 and perlin_vines_fine:get_3d(pos) > vine_threshold and data[p_pos] == c_air then
local rdir = {}
rdir.x = -dirs[d].x
rdir.y = dirs[d].y
rdir.z = -dirs[d].z
local param2 = minetest_dir_to_wallmounted(rdir)
-- Determine growth direction
local grow_upwards = false
-- Only possible on the wood, not on the leaves
if i == 1 then
grow_upwards = perlin_vines_upwards:get_3d(pos) > 0.8
end
if grow_upwards then
-- Grow vines up 1-4 nodes, even through jungleleaves.
-- This may give climbing access all the way to the top of the tree :-)
-- But this will be fairly rare.
local length = math_ceil(math_abs(perlin_vines_length:get_3d(pos)) * 4)
for l=0, length-1 do
local t_pos = area:index(treepos.x, treepos.y, treepos.z)
if (data[p_pos] == c_air or data[p_pos] == c_jungleleaves or data[p_pos] == c_leaves) and mcl_core.supports_vines(minetest.get_name_from_content_id(data[t_pos])) then
data[p_pos] = c_vine
param2_data[p_pos] = param2
vm_context.write = true
else
break
end
pos.y = pos.y + 1
p_pos = area:index(pos.x, pos.y, pos.z)
treepos.y = treepos.y + 1
end
else
-- Grow vines down, length between 1 and maxvinelength
local length = math_ceil(math_abs(perlin_vines_length:get_3d(pos)) * maxvinelength)
for l=0, length-1 do
if data[p_pos] == c_air then
data[p_pos] = c_vine
param2_data[p_pos] = param2
vm_context.write = true
else
break
end
pos.y = pos.y - 1
p_pos = area:index(pos.x, pos.y, pos.z)
end
end
end
end
end
end
end
mcl_mapgen.register_on_generated(generate_tree_decorations, 0)