250 lines
8.2 KiB
Lua
250 lines
8.2 KiB
Lua
-- mods/australia/voxel.lua
|
|
|
|
-- This is only used to handle cases the decoration manager can't, such as
|
|
-- more ore in specific biomes.
|
|
|
|
-- Define perlin noises used in this mapgen by default
|
|
aus.noises = {}
|
|
|
|
-- Noise 22 : Cave blend 2D
|
|
aus.noises[22] = {offset = 0.0, scale = 0.1, spread = {x = 8, y = 8, z = 8}, seed = 4023, octaves = 2, persist = 1.0, lacunarity = 2.0}
|
|
|
|
-- Noise 23 : Cave noise 2D
|
|
aus.noises[23] = {offset = 0.0, scale = 1.0, spread = {x = 400, y = 400, z = 400}, seed = 903, octaves = 3, persist = 0.5, lacunarity = 2.0}
|
|
|
|
-- function to get noisemaps
|
|
function aus.noisemap(i, minp, chulens)
|
|
local obj = minetest.get_perlin_map(aus.noises[i], chulens)
|
|
if minp.z then
|
|
return obj:get3dMap_flat(minp)
|
|
else
|
|
return obj:get2dMap_flat(minp)
|
|
end
|
|
end
|
|
|
|
-- useful function to convert a 3D pos to 2D
|
|
function pos2d(pos)
|
|
if type(pos) == "number" then
|
|
return {x = pos, y = pos}
|
|
elseif pos.z then
|
|
return {x = pos.x, y = pos.z}
|
|
else
|
|
return {x = pos.x, y = pos.y}
|
|
end
|
|
end
|
|
|
|
-- Define content IDs
|
|
-- A content ID is a number that represents a node in the core of Minetest.
|
|
-- Every nodename has its ID.
|
|
-- The VoxelManipulator uses content IDs instead of nodenames.
|
|
|
|
local node = {}
|
|
|
|
local nodes = {
|
|
-- Ground nodes
|
|
{"stone", "default:stone"},
|
|
{"dirt", "default:dirt"},
|
|
{"sand", "default:sand"},
|
|
|
|
-- Liquids
|
|
{"river_water_source", "default:river_water_source"},
|
|
{"dirty_river_water_source", "australia:dirty_river_water_source"},
|
|
{"water_source", "default:water_source"},
|
|
|
|
-- Air and Ignore
|
|
{"air", "air"},
|
|
{"ignore", "ignore"},
|
|
|
|
-- Resources
|
|
{"coalblock", "default:coalblock"},
|
|
{"copper", "default:stone_with_copper"},
|
|
{"diamond", "default:stone_with_diamond"},
|
|
{"gold", "default:stone_with_gold"},
|
|
{"iron", "default:stone_with_iron"},
|
|
}
|
|
|
|
for _, i in pairs(nodes) do
|
|
node[i[1]] = minetest.get_content_id(i[2])
|
|
end
|
|
|
|
local coal_biomes = {"victorian_forests", "great_dividing_range", "eastern_coasts"}
|
|
local copper_biomes = {"flinders_lofty", "gulf_of_carpentaria"}
|
|
local diamond_biomes = {"kimberley"}
|
|
local gold_biomes = {"goldfields_esperence", "victorian_forests"}
|
|
local iron_biomes = {"pilbara"}
|
|
|
|
-- Create a table of biome ids, so I can use the biomemap.
|
|
if not aus.biome_ids then
|
|
aus.biome_ids = {}
|
|
for name, desc in pairs(minetest.registered_biomes) do
|
|
local i = minetest.get_biome_id(desc.name)
|
|
aus.biome_ids[i] = desc.name
|
|
end
|
|
end
|
|
|
|
-- the mapgen function
|
|
function aus.generate(minp, maxp, seed)
|
|
|
|
-- minp and maxp strings, used by logs
|
|
local minps, maxps = minetest.pos_to_string(minp), minetest.pos_to_string(maxp)
|
|
|
|
-- The VoxelManipulator, a complicated but speedy method to set many nodes at the same time
|
|
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
|
local heightmap = minetest.get_mapgen_object("heightmap")
|
|
-- local heatmap = minetest.get_mapgen_object("heatmap")
|
|
local gennotify = minetest.get_mapgen_object("gennotify")
|
|
--print(dump(gennotify))
|
|
local water_level = 1
|
|
|
|
local data = vm:get_data() -- data is the original array of content IDs (solely or mostly air)
|
|
-- Be careful: emin ≠ minp and emax ≠ maxp !
|
|
-- The data array is not limited by minp and maxp. It exceeds it by 16 nodes in the 6 directions.
|
|
-- The real limits of data array are emin and emax.
|
|
-- The VoxelArea is used to convert a position into an index for the array.
|
|
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
|
local ystride = area.ystride -- Tip : the ystride of a VoxelArea is the number to add to the array index to get the index of the position above. It's faster because it avoids to completely recalculate the index.
|
|
local zstride = area.zstride
|
|
|
|
local chulens = vector.add(vector.subtract(maxp, minp), 1) -- Size of the generated area, used by noisemaps
|
|
local minp2d = pos2d(minp)
|
|
|
|
-- The biomemap is a table of biome index numbers for each horizontal
|
|
-- location. It's created in the mapgen, and is right most of the time.
|
|
-- It's off in about 1% of cases, for various reasons.
|
|
-- Bear in mind that biomes can change from one voxel to the next.
|
|
local biomemap = minetest.get_mapgen_object("biomemap")
|
|
|
|
-- Calculate the noise values
|
|
local n22 = aus.noisemap(22, minp2d, chulens)
|
|
local n23 = aus.noisemap(23, minp2d, chulens)
|
|
|
|
local node_match_cache = {}
|
|
|
|
-- the mapgen algorithm
|
|
local index_2d = 0
|
|
local write = false
|
|
local relight = false
|
|
|
|
for x = minp.x, maxp.x do -- for each YZ plane
|
|
for z = minp.z, maxp.z do -- for each vertical line in this plane
|
|
index_2d = index_2d + 1
|
|
|
|
local index_3d = area:index(x, maxp.y, z) -- index of the data array, matching the position {x, y, z}
|
|
local air_count = 0
|
|
local ground = math.max(heightmap[index_2d], 0) - 5
|
|
|
|
for y = maxp.y, minp.y, -1 do -- for each node in vertical line
|
|
local index_3d_below = index_3d - ystride
|
|
local index_3d_above = index_3d + ystride
|
|
local surround = true
|
|
|
|
-- Determine if a plant/dirt block can be placed without showing.
|
|
-- Avoid the edges of the chunk, just to make things easier.
|
|
if y < maxp.y and x > minp.x and x < maxp.x and z > minp.z and z < maxp.z and (data[index_3d] == node["sand"] or data[index_3d] == node["dirt"]) then
|
|
if data[index_3d_above] == node["river_water_source"] or data[index_3d_above] == node["water_source"] then
|
|
-- Check to make sure that a plant root is fully surrounded.
|
|
-- This is due to the kludgy way you have to make water plants
|
|
-- in minetest, to avoid bubbles.
|
|
for x1 = -1,1,2 do
|
|
local n = data[index_3d+x1]
|
|
if n == node["river_water_source"] or n == node["water_source"] or n == node["air"] then
|
|
surround = false
|
|
end
|
|
end
|
|
for z1 = -zstride,zstride,2*zstride do
|
|
local n = data[index_3d+z1]
|
|
if n == node["river_water_source"] or n == node["water_source"] or n == node["air"] then
|
|
surround = false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Extra resources in ground per biome.
|
|
if y < ground and (data[index_3d] == node["air"] or data[index_3d] == node["river_water_source"] or data[index_3d] == node["dirty_river_water_source"] or data[index_3d] == node["water_source"]) then
|
|
relight = true
|
|
|
|
local biome = aus.biome_ids[biomemap[index_2d]]
|
|
local stone_type = node["stone"]
|
|
local stone_depth = 1
|
|
local n23_val = n23[index_2d] + n22[index_2d]
|
|
if table.contains(coal_biomes, biome) and n23_val < 0.1 then
|
|
stone_type = node["coalblock"]
|
|
stone_depth = 2
|
|
elseif table.contains(copper_biomes, biome) and n23_val < 0.4 then
|
|
stone_type = node["copper"]
|
|
elseif table.contains(diamond_biomes, biome) and n23_val < 0.2 then
|
|
stone_type = node["diamond"]
|
|
elseif table.contains(gold_biomes, biome) and n23_val < 0.3 then
|
|
stone_type = node["gold"]
|
|
elseif table.contains(iron_biomes, biome) and n23_val < 0.6 then
|
|
stone_type = node["iron"]
|
|
else
|
|
stone_type = node["stone"]
|
|
end
|
|
|
|
-- Change stone per biome.
|
|
if data[index_3d_below] == node["stone"] then
|
|
data[index_3d_below] = stone_type
|
|
if stone_depth == 2 then
|
|
data[index_3d_below - ystride] = stone_type
|
|
end
|
|
write = true
|
|
end
|
|
if data[index_3d_above] == node["stone"] then
|
|
data[index_3d_above] = stone_type
|
|
if stone_depth == 2 then
|
|
data[index_3d_above + ystride] = stone_type
|
|
end
|
|
write = true
|
|
end
|
|
|
|
if data[index_3d] == node["air"] then
|
|
air_count = air_count + 1
|
|
end
|
|
end
|
|
|
|
if data[index_3d] ~= node["air"] then
|
|
air_count = 0
|
|
end
|
|
index_3d = index_3d_below
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
-- execute voxelmanip boring stuff to write to the map...
|
|
if write then
|
|
vm:set_data(data)
|
|
end
|
|
|
|
if write then
|
|
-- probably not necessary
|
|
if relight then
|
|
--vm:set_lighting({day = 10, night = 10})
|
|
end
|
|
|
|
-- This seems to be necessary to avoid lighting problems.
|
|
vm:calc_lighting()
|
|
|
|
-- probably not necessary
|
|
--vm:update_liquids()
|
|
end
|
|
|
|
if write then
|
|
vm:write_to_map()
|
|
end
|
|
|
|
-- Deal with memory issues. This, of course, is supposed to be automatic.
|
|
local mem = math.floor(collectgarbage("count")/1024)
|
|
if mem > 500 then
|
|
print("MOD: Australia is manually collecting garbage as memory use has exceeded 500K.")
|
|
collectgarbage("collect")
|
|
end
|
|
end
|
|
|
|
|
|
-- Call the mapgen function aus.generate on mapgen.
|
|
-- (located in voxel.lua)
|
|
minetest.register_on_generated(aus.generate)
|