--[[ Everness. Never ending discovery in Everness mapgen. Copyright (C) 2024 SaKeL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. --]] -- Localize data buffer table outside the loop, to be re-used for all -- mapchunks, therefore minimising memory use. local data = {} local p2data = {} minetest.register_on_generated(function(minp, maxp, blockseed) -- Start time of mapchunk generation. -- local t0 = os.clock() local rand = PcgRandom(blockseed) -- Array containing the biome IDs of nodes in the most recently generated chunk by the current mapgen local biomemap = minetest.get_mapgen_object('biomemap') -- Table mapping requested generation notification types to arrays of positions at which the corresponding generated structures are located within the current chunk local gennotify = minetest.get_mapgen_object('gennotify') -- Load the voxelmanip with the result of engine mapgen local vm, emin, emax = minetest.get_mapgen_object('voxelmanip') -- 'area' is used later to get the voxelmanip indexes for positions local area = VoxelArea:new({ MinEdge = emin, MaxEdge = emax }) -- Get the content ID data from the voxelmanip in the form of a flat array. -- Set the buffer parameter to use and reuse 'data' for this. vm:get_data(data) -- Raw `param2` data read into the `VoxelManip` object vm:get_param2_data(p2data) -- Side length of mapchunk local shared_args = {} -- -- on_data -- -- read/write to `data` what will be eventually saved (set_data) -- used for voxelmanip `data` manipulation for _, def in ipairs(Everness.on_generated_queue) do if def.can_run(biomemap) and def.on_data then shared_args[def.name] = shared_args[def.name] or {} def.on_data(minp, maxp, area, data, p2data, gennotify, rand, shared_args[def.name]) end end -- set data after they have been manipulated (from above) vm:set_data(data) vm:set_param2_data(p2data) -- -- after_set_data -- -- read-only (but cant and should not manipulate) voxelmanip `data` -- used for `place_schematic_on_vmanip` which will invalidate `data` -- therefore we are doing it after we set the data for _, def in ipairs(Everness.on_generated_queue) do if def.can_run(biomemap) and def.after_set_data then shared_args[def.name] = shared_args[def.name] or {} def.after_set_data(minp, maxp, vm, area, data, p2data, gennotify, rand, shared_args[def.name]) end end -- Set the lighting within the `VoxelManip` to a uniform value vm:set_lighting({ day = 0, night = 0 }, minp, maxp) -- Calculate lighting for what has been created. vm:calc_lighting() -- Liquid nodes were placed so set them flowing. vm:update_liquids() -- Write what has been created to the world. vm:write_to_map() -- -- after_write_to_map -- -- Cannot read/write voxelmanip or its data -- Used for direct manipulation of the world chunk nodes where the -- definitions of nodes are available and node callback can be executed -- or e.g. for `minetest.fix_light` for _, def in ipairs(Everness.on_generated_queue) do if def.can_run(biomemap) and def.after_write_to_map then shared_args[def.name] = shared_args[def.name] or {} def.after_write_to_map(shared_args[def.name], gennotify, rand) end end -- Print generation time of this mapchunk. -- local chugent = math.ceil((os.clock() - t0) * 1000) -- print('[Everness] Mapchunk generation time ' .. chugent .. ' ms') end) local mpath = minetest.get_modpath('everness') -- -- Giant Sequoia Tree -- local sequoia_tree_schem = minetest.get_modpath('everness') .. '/schematics/everness_giant_sequoia_tree.mts' abdecor.register_advanced_decoration('everness_giant_sequoia_tree',{ target = { place_on = { 'default:dirt_with_coniferous_litter', 'default:dirt_with_snow', 'default:dirt_with_dry_grass', }, spawn_by = { 'default:dirt_with_coniferous_litter', 'default:dirt_with_snow', 'default:dirt_with_dry_grass', }, num_spawn_by = 8, sidelen = 80, fill_ratio = 0.000095, y_max = 31000, y_min = 8, biomes = { 'mesa', 'taiga', 'coniferous_forest', }, }, fn = function(mapgen) -- Get provided values local pos = mapgen.pos local va = mapgen.voxelarea local vdata = mapgen.data local ystride = va.ystride local zstride = va.zstride -- Check that there is likely enough space to place a tree local vpos = va:index(pos.x,pos.y,pos.z) for i = 2, 20 do -- y if vdata[vpos + ystride * i] ~= minetest.CONTENT_AIR then return -- not enough ceiling clearance end end for i = -6, 6 do -- x if vdata[vpos + i] == minetest.CONTENT_AIR then return -- not enough space in the x dimension end end for i = -6, 6 do -- z if vdata[vpos + i * zstride] == minetest.CONTENT_AIR then return -- not enough space in the z dimension end end -- Roughly enough space, emerge mapchunks and place a sequoia tree minetest.emerge_area( vector.new(pos.x - 12, pos.y, pos.z - 12), vector.new(pos.x + 12, pos.y + 75, pos.z + 12), function(blockpos, action, calls_remaining, param) Everness:emerge_area(blockpos, action, calls_remaining, param) end, { callback = function() -- Place sequoia tree minetest.place_schematic( pos, sequoia_tree_schem, 'random', nil, true, 'place_center_x, place_center_z' ) -- Fix lighting minetest.fix_light( { x = pos.x - 12, y = pos.y, z = pos.z - 12}, { x = pos.x + 12, y = pos.y + 75, z = pos.z + 12}, true ) end } ) end, }) -- -- Underground Mese Tree -- local mese_tree_schem = minetest.get_modpath('everness') .. '/schematics/everness_mese_tree.mts' abdecor.register_advanced_decoration('everness_mese_tree_underground',{ target = { place_on = 'everness:moss_block', sidelen = 80, fill_ratio = 0.0000125, y_max = -300, y_min = -31000, biomes = asuna.features.cave.bamboo, flags = 'all_floors', }, fn = function(mapgen) -- Get provided values local pos = mapgen.pos local va = mapgen.voxelarea local vdata = mapgen.data local ystride = va.ystride local zstride = va.zstride -- Check that there is likely enough space to place a tree local vpos = va:index(pos.x,pos.y,pos.z) for i = 2, 10 do -- y if vdata[vpos + ystride * i] ~= minetest.CONTENT_AIR then return -- not enough ceiling clearance end end vpos = vpos + ystride * 5 for i = -3, 3 do -- x if vdata[vpos + i] ~= minetest.CONTENT_AIR then return -- not enough space in the x dimension end end for i = -3, 3 do -- z if vdata[vpos + i * zstride] ~= minetest.CONTENT_AIR then return -- not enough space in the z dimension end end -- Roughly enough space, place a mese tree mapgen.place_schematic({ pos = pos, schematic = mese_tree_schem, flags = 'place_center_x,place_center_z', }) -- Fix lighting mapgen.calc_lighting( { x = pos.x - 3, y = pos.y, z = pos.z - 3 }, { x = pos.x + 3, y = pos.y + 10, z = pos.z + 3 }, true ) end, flags = { schematic = true, } })