2016-04-10 20:17:20 -07:00
-- 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 " } ,
2016-04-21 20:35:41 -07:00
{ " muddy_river_water_source " , " australia:muddy_river_water_source " } ,
2016-04-10 20:17:20 -07:00
{ " 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 " } ,
2016-04-21 20:35:41 -07:00
2016-04-10 20:17:20 -07:00
}
for _ , i in pairs ( nodes ) do
node [ i [ 1 ] ] = minetest.get_content_id ( i [ 2 ] )
end
-- 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 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
2016-04-21 20:35:41 -07:00
local index_3d , air_count , ground
local index_3d_below , index_3d_above , surround
local biome , sr
local stone_type , stone_depth , n23_val
2016-04-10 20:17:20 -07:00
2016-04-21 20:35:41 -07:00
for z = minp.z , maxp.z do -- for each YZ plane
for x = minp.x , maxp.x do -- for each vertical line in this plane
2016-04-10 20:17:20 -07:00
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
-- 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
2016-04-21 20:35:41 -07:00
if data [ index_3d_above ] == node [ " river_water_source " ] or data [ index_3d_above ] == node [ " muddy_river_water_source " ] or data [ index_3d_above ] == node [ " water_source " ] then
2016-04-10 20:17:20 -07:00
-- 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 ]
2016-04-21 20:35:41 -07:00
if n == node [ " river_water_source " ] or n == node [ " muddy_river_water_source " ] or n == node [ " water_source " ] or n == node [ " air " ] then
2016-04-10 20:17:20 -07:00
surround = false
end
end
for z1 = - zstride , zstride , 2 * zstride do
local n = data [ index_3d + z1 ]
2016-04-21 20:35:41 -07:00
if n == node [ " river_water_source " ] or n == node [ " muddy_river_water_source " ] or n == node [ " water_source " ] or n == node [ " air " ] then
2016-04-10 20:17:20 -07:00
surround = false
end
end
end
-- Extra resources in ground per biome.
2016-04-21 20:35:41 -07:00
if y < ground and ( data [ index_3d ] == node [ " air " ] or data [ index_3d ] == node [ " river_water_source " ] or data [ index_3d ] == node [ " muddy_river_water_source " ] or data [ index_3d ] == node [ " water_source " ] ) then
2016-04-10 20:17:20 -07:00
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 ]
-- 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
-- This seems to be necessary to avoid lighting problems.
vm : calc_lighting ( )
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.
minetest.register_on_generated ( aus.generate )