Initial Commit

master
qwertymine3 2015-11-16 21:42:39 +00:00
commit bb188a41fa
7 changed files with 1321 additions and 0 deletions

120
distance.lua Normal file
View File

@ -0,0 +1,120 @@
vcnlib.geometry = {}
local geo = vcnlib.geometry
local abs = math.abs
local floor = math.floor
local hash_pos = minetest.hash_node_position
local function greatest(x,y,z)
if x>y then
if x>z then
return x
else
return z
end
else
if y>z then
return y
else
return z
end
end
end
geo.manhattan = {
_2d = function(a,b)
local x=abs(a.x-b.x)
local z=abs(a.z-b.z)
return x+z
end,
_3d = function(a,b)
local x=abs(a.x-b.x)
local y=abs(a.y-b.y)
local z=abs(a.z-b.z)
return x+y+z
end,
}
geo.chebyshev = {
_2d = function(a,b)
local x=abs(a.x-b.x)
local z=abs(a.z-b.z)
return greatest(x,0,z)
end,
_3d = function(a,b)
local x=abs(a.x-b.x)
local y=abs(a.y-b.y)
local z=abs(a.z-b.z)
return greatest(x,y,z)
end,
}
geo.euclidean = {
_2d = function(a,b)
local x=abs(a.x-b.x)
local z=abs(a.z-b.z)
return math.sqrt((x*x)+(z*z))
end,
_2d_fast = function(a,b)
local x=abs(a.x-b.x)
local z=abs(a.z-b.z)
return (x*x)+(z*z)
end,
_3d = function(a,b)
local x=abs(a.x-b.x)
local y=abs(a.y-b.y)
local z=abs(a.z-b.z)
return math.sqrt((x*x)+(y*y)+(z*z))
end,
_3d_fast = function(a,b)
local x=abs(a.x-b.x)
local y=abs(a.y-b.y)
local z=abs(a.z-b.z)
return (x*x)+(y*y)+(z*z)
end,
}
geo.oddprod = {
_2d = function(a,b)
local x=abs(a.x-b.x)
local z=abs(a.z-b.z)
if x <= 1 then
x=1
end
if z <= 1 then
z=1
end
return abs(x*z)
end,
_3d = function(a,b)
local x=abs(a.x-b.x)
local y=abs(a.y-b.y)
local z=abs(a.z-b.z)
if x <= 1 then
x=1
end
if y <= 1 then
y=1
end
if z <= 1 then
z=1
end
return abs(x*y*z)
end,
}
local get_distance_function = function (geometry, dimensions)
if geo[geometry] then
if dimensions == 3 then
return geo[geometry]._3d
else
return geo[geometry]._2d
end
else
return nil
end
end
vcnlib.get_distance_function = get_distance_function

860
init.lua Normal file
View File

@ -0,0 +1,860 @@
vcnlib = {}
vcnlib.layers = {}
--Layer def
-- name
-- string
-- dimensions
-- 2 or 3
-- block_size
-- vector - norm 5^3 or nil
-- sector_lengths
-- vector - norm 300^3 or 2000^3
-- scale
-- integer - the sector lengths are multiplied by this, but the
-- noise produced has a lower resolution
-- biome_types
-- table of strings- random,multi-map,multi-tolerance-map,default-biome
-- biome_type_options
-- table - tolerances for heatmap
-- geometry
-- string - euclidean,manhattan,chebyshev
--
--Layer in mem
-- cache
-- table of tables
-- add_biome
-- function to add biomes to the layer
--
--
--Point in mem
-- pos
-- vector
-- biome
-- biome def table
--Returns the biome of the closest point from a table
--Must ensure that points cover the Moore environment of the sector
--[[
--TODO list
--Docs
--add more types of noise - cubic cell noise especially
--]]
--functions defined in local scope for performance
local minetest = minetest
local abs = math.abs
local floor = math.floor
local hash_pos = minetest.hash_node_position
dofile(minetest.get_modpath("vcnlib").."/distance.lua")
dofile(minetest.get_modpath("vcnlib").."/maps.lua")
--normal vector.add has a check for b not being a table, I don't need this
local vector_add = function(a,b)
return {x=a.x+b.x,y=a.y+b.y,z=a.z+b.z}
end
--this could be stored in the layer - possibly tracked at biome addition
local get_biome_num = function(layer)
return layer.biome_number
end
--sector 0,0,0 has a smallest point at 0,0,0
local sector_to_pos = function(sector,layer)
local lengths = layer.sector_lengths
local pos = {}
if layer.dimensions == 3 then
pos.x = lengths.x * sector.x
pos.y = lengths.y * sector.y
pos.z = lengths.z * sector.z
else
pos.x = lengths.x * sector.x
pos.y = 0
pos.z = lengths.z * sector.z
end
return pos
end
--add function to api
vcnlib.sector_to_pos = sector_to_pos
--point 0,0,0 is in sector 0,0,0
local pos_to_sector = function(pos,layer)
local lengths = layer.sector_lengths
local sector = {x=pos.x,y=pos.y,z=pos.z}
sector.x = floor(sector.x/lengths.x)
sector.z = floor(sector.z/lengths.z)
if layer.dimensions == 3 then
sector.y = floor(sector.y/lengths.y)
else
sector.y = 0
end
return sector
end
vcnlib.pos_to_sector = pos_to_sector
--This is hot code, so checks are kept out of the looping sections
--so there is a lot of code duplication
local find_closest = function(pos,points,dist_func)
local dist = nil
local mini = math.huge
local biome = nil
for i=1,#points do
local point = points[i]
dist = dist_func(pos,point.pos)
if dist < mini then
mini = dist
biome = point.biome
end
end
return biome
end
--block locations must start at (0,0,0)
--for 2d use (x,y) rather than (x,0,z)
local blockfiller = function(blockdata,blocksize,table,tablesize,blockstart)
local tableit = blockstart
local ybuf,zbuf = tablesize.x - blocksize.x,(tablesize.y - blocksize.y)*tablesize.x
local x,y,z = 1,1,1
local blocklength = blocksize.x*blocksize.y*(blocksize.z or 1)
for i=1,blocklength do
if x > blocksize.x then
x = 1
y = y + 1
tableit = tableit + ybuf
end
if y > blocksize.y then
y = 1
z = z + 1
tableit = tableit + zbuf
end
table[tableit] = blockdata[i]
tableit = tableit + 1
x = x + 1
end
end
--block locations must start at (0,0,0)
local blockfiller_2d = function(blockdata,blocksize,table,tablesize,blockstart)
local tableit = blockstart
local zbuf = tablesize.x - blocksize.x
local x,z = 1,1
local blocklength = blocksize.x*blocksize.z
for i=1,blocklength do
if x > blocksize.x then
x = 1
z = z + 1
tableit = tableit + zbuf
end
table[tableit] = blockdata[i]
tableit = tableit + 1
x = x + 1
end
end
--Uses PcgRandom for better range - a 32 bit random would limit sector sizes to
-- 600^3 due to randomness issues
local generate_points = function(sector,seed,layer)
local hash = hash_pos(sector)
local offset = layer.seed_offset
local prand = PcgRandom(hash + (seed + offset) % 100000)
--Distribution is completely user defined
local point_dist = layer.point_distribution
local num = prand:next(point_dist.random_min,point_dist.random_max)
local set = false
for i=#point_dist,1,-1 do
if num >= point_dist[i] then
num = i
set = true
break
end
end
--If no suitable number of points is found, 1 is set as a fallback
if not set then
num = 1
end
--Generate each point
local seen = {}
local points = {}
while num > 0 do
--The points are aligned to 0.1 of a block
--This used to be to 1 block, but having multiple points at
--the same distance was causing artifacts with the experimental gen
local x = prand:next(0,(layer.sector_lengths.x-1)*10)
local y
if layer.dimensions == 3 then
y = prand:next(0,(layer.sector_lengths.y-1)*10)
else
y = 0
end
local z = prand:next(0,(layer.sector_lengths.z-1)*10)
local pos = {x=x/10,y=y/10,z=z/10}
local hashed = hash_pos(pos)
if not seen[hashed] then
pos = vector_add(pos,sector_to_pos(sector,layer))
table.insert(points,pos)
seen[hashed] = pos
end
num = num - 1
end
--The random number generator is returned for use in adding other
--properties to the points - biomes
return points , prand
end
--This function is used to get the maps required for generate_biomed_points below
--The in-built maps have to be treated differently to the custom ones, as no
--extra data can be stored in the perlin map userdata
local function get_point_maps(point, layer)
local maps = {}
for i,v in ipairs(layer.biome_maps) do
if v.perlin then
if v.dims == 3 then
maps[i] = v.perlin:get3d(point)
else
local point = {x=point.x,y=point.z}
maps[i] = v.perlin:get2d(point)
end
else
maps[i] = v:get_noise(point)
end
end
return maps
end
--This is a wrapper around generate_points - this adds biomes and doesn't return the random
--number generator
local generate_biomed_points = function(sector,seed,layer)
local hash = hash_pos(sector)
--This is a cache for storing points that were already generated
--this should improve performance - but profiling breaks it
if layer.cache[hash] then
return layer.cache[hash]
end
local points,prand = generate_points(sector,seed,layer)
local biome_types = layer.biome_types
local ret = {}
for i=1,#points do
local point = points[i]
local biome = nil
local maps = nil
for method=1,#biome_types do
local biome_meth = biome_types[method]
if biome_meth == "random" then
local num = prand:next(1,get_biome_num(layer))
biome = layer.biomes[num]
elseif biome_meth == "multi-map" then
if not maps then
maps = get_point_maps(point, layer)
end
local min_dist = math.huge
for j,k in ipairs(layer.biome_defs) do
local this_dist = 0
for l,m in ipairs(maps) do
this_dist = this_dist + abs(k[l] - m)
end
if this_dist < min_dist then
biome = k.name
min_dist = this_dist
end
end
elseif biome_meth == "multi-tolerance-map" then
local tol = layer.tolerance
if not maps then
maps = get_point_maps(point, layer)
end
local biomes = {}
for j,k in ipairs(layer.biome_defs) do
local add = true
for l,m in ipairs(maps) do
local diff = abs(k[l] - m)
if diff > tol[l] then
add = false
break
end
end
if add then
table.insert(biomes,k)
end
end
local bionum = #biomes
if bionum ~= 0 then
biome = biomes[prand:next(1,bionum)].name
end
else
biome = biome_meth
end
if biome then
break
end
end
table.insert(ret,{
pos = point,
biome = biome,
})
end
layer.cache[hash] = ret
return ret
end
local generate_block = function(blocksize,blockcentre,blockmin,layer,seed,byot)
local points = {}
local block = byot or {}
local index = 1
local dims = layer.dimensions
local geo = layer.geometry
local blockmax = {x=blockmin.x+(blocksize.x-1),y=blockmin.y+(blocksize.y -1)
,z=blockmin.z+(blocksize.z-1)}
local sector = pos_to_sector(blockcentre,layer)
local get_dist = layer.get_dist
if dims == 3 then
local x,y,z = -1,-1,-1
for i=1,27 do
if x > 1 then
x = -1
y = y + 1
end
if y > 1 then
y = -1
z = z + 1
end
local temp = generate_biomed_points(vector_add(sector,{x=x,y=y,z=z})
,seed,layer)
for i,v in ipairs(temp) do
points[index] = v
v.dist = get_dist(blockcentre,v.pos)
index = index + 1
end
x = x + 1
end
else
local x,z = -1,-1
for i=1,9 do
if x > 1 then
x = -1
z = z + 1
end
local temp = generate_biomed_points(vector_add(sector,{x=x,y=0,z=z})
,seed,layer)
for i,v in ipairs(temp) do
points[index] = v
v.dist = get_dist(blockcentre,v.pos)
index = index + 1
end
x = x + 1
end
end
table.sort(points,function(a,b) return a.dist < b.dist end)
local to_nil = false
local max_dist = points[1].dist + get_dist(blockmin,blockcentre)
for i=1,#points do
if to_nil then
points[i] = nil
elseif points[i].dist > max_dist then
to_nil = true
end
end
--Switch to fast distance type when doing comparison only calcs
get_dist = layer.get_dist_fast
if #points == 1 then
if dims == 3 then
local tablesize = blocksize.x*blocksize.y*blocksize.z
local x,y,z = blockmin.x,blockmin.y,blockmin.z
local biome = point[1].biome
for i = 1,tablesize do
if x > blockmax.x then
x = blockmin.x
y = y + 1
end
if y > blockmax.y then
y = blockmin.y
z = z + 1
end
block[i] = biome
x = x + 1
end
else
local tablesize = blocksize.x*blocksize.z
local x,y = blockmin.x,blockmin.z
local biome = point[1].biome
for i = 1,tablesize do
if x> blockmax.x then
x = blockmin.x
y = y + 1
end
block[i] = biome
x = x + 1
end
end
elseif dims == 3 then
local tablesize = blocksize.x*blocksize.y*blocksize.z
local x,y,z = blockmin.x,blockmin.y,blockmin.z
for i = 1,tablesize do
if x > blockmax.x then
x = blockmin.x
y = y + 1
end
if y > blockmax.y then
y = blockmin.y
z = z + 1
end
block[i] = find_closest({x=x,y=y,z=z}
,points,get_dist)
x = x + 1
end
else
local tablesize = blocksize.x*blocksize.z
local x,y = blockmin.x,blockmin.z
for i = 1,tablesize do
if x> blockmax.x then
x = blockmin.x
y = y + 1
end
block[i] = find_closest({x=x,y=y,z=z}
,points,get_dist)
x = x + 1
end
end
return block
end
local shared_block_byot = {}
--map is generated in blocks
--this allows for distance testing to reduce the number of points to test
local get_biome_map_3d_experimental = function(minp,maxp,layer,seed,byot)
--normal block size
local blsize = layer.blocksize or {x=5,y=5,z=5}
local halfsize = {x=blsize.x/2,y=blsize.y/2,z=blsize.z/2}
local centre = {x=minp.x+halfsize.x,y=minp.y+halfsize.y,z=minp.z+halfsize.z}
--the size of this block
local blocksize = {x=blsize.x,y=blsize.y,z=blsize.z}
local blockmin = {x=minp.x,y=minp.y,z=minp.z}
local mapsize = {x=maxp.x-minp.x+1,y=maxp.y-minp.y+1,z=maxp.z-minp.z+1}
--bring your own table - reduce garbage collections
local map = byot or {}
local block_byot = nil
if byot then
block_byot = shared_block_byot
end
for z=minp.z,maxp.z,blsize.z do
centre.z = z + halfsize.z
blockmin.z = z
if z + (blsize.z - 1) > maxp.z then
blocksize.z = blsize.z - ((z + (blsize.z - 1)) - maxp.z)
centre.z = z + blocksize.z/2
end
for y=minp.y,maxp.y,blsize.y do
centre.y = y + halfsize.y
blockmin.y = y
if y + (blsize.y - 1) > maxp.y then
blocksize.y = blsize.y - ((y + (blsize.y - 1)) - maxp.y)
centre.y = y + blocksize.y/2
end
for x=minp.x,maxp.x,blsize.x do
centre.x = x + halfsize.x
blockmin.x = x
if x + (blsize.x - 1) > maxp.x then
blocksize.x = blsize.x - ((x + (blsize.x -1)) - maxp.x)
centre.x = x + blocksize.x/2
end
local temp = generate_block(blocksize,centre,blockmin
,layer,seed,block_byot)
local blockstart = blockmin.x - minp.x + 1
+ (blockmin.y - minp.y)*mapsize.x
+ (blockmin.z - minp.z)*mapsize.x*mapsize.y
blockfiller(temp,blocksize,map,mapsize,blockstart)
end
end
end
return map
end
vcnlib.experimental_3d = get_biome_map_3d_experimental
local get_biome_map_2d_experimental = function(minp,maxp,layer,seed,byot)
local blsize = layer.blocksize or {x=5,y=0,z=5}
local halfsize = {x=blsize.x/2,y=0,z=blsize.z/2}
local centre = {x=minp.x+halfsize.x,y=0,z=minp.z+halfsize.z}
local blocksize = {x=blsize.x,y=0,z=blsize.z}
local blockmin = {x=minp.x,y=0,z=minp.z}
local mapsize = {x=maxp.x-minp.x+1,y=0,z=maxp.z-minp.z+1}
local map = byot or {}
local block_byot
if byot then
block_byot = shared_block_byot
end
for z=minp.z,maxp.z,blsize.z do
centre.z = z + halfsize.z
blockmin.z = z
if z + (blsize.z - 1) > maxp.z then
blocksize.z = blsize.z - ((z + (blsize.z - 1)) - maxp.z)
centre.z = z + blocksize.z/2
end
for x=minp.x,maxp.x,blsize.x do
centre.x = x + halfsize.x
blockmin.x = x
if x + (blsize.x - 1) > maxp.x then
blocksize.x = blsize.x - ((x + (blsize.x -1)) - maxp.x)
centre.x = x + blocksize.x/2
end
local temp = generate_block(blocksize,centre,blockmin
,layer,seed,block_byot)
local blockstart = blockmin.x - minp.x + 1
+ (blockmin.z - minp.z)*mapsize.x
blockfiller_2d(temp,blocksize,map,mapsize,blockstart)
end
end
return map
end
vcnlib.experimental_2d = get_biome_map_2d_experimental
local function init_maps(layer)
--Setup layer maps if there are any
for map_index,def_table in ipairs(layer.biome_maps) do
--Add layer offset to map seed offset
if def_table.seed_offset then
def_table.seed_offset = def_table.seed_offset + layer.seed_offset
end
--Variable to contruct the final map object
local biome_map = nil
--The noise type is solely detrmined by the map_type
if def_table.map_type == "perlin" then
biome_map = {}
biome_map.dimensions = def_table.dimensions or 2
biome_map.perlin = minetest.get_perlin(def_table)
else
biome_map = vcnlib.get_map_object(def_table)
end
--Replace def_table with map object
layer.biome_maps[map_index] = biome_map
end
layer.maps_init = true
end
--simple test to find the biome of a node
--used as the basis of the simple map generation methods
local get_node_biome = function(pos,seed,layer)
local sector = pos_to_sector(pos,layer)
local dims = layer.dimensions
local points = {}
local x,y,z = -1,-1,-1
local index = 1
--Check that the maps have been initialised
if not layer.maps_init then
init_maps(layer)
end
if dims == 3 then
for i=1,27 do
if x > 1 then
x = -1
y = y + 1
end
if y > 1 then
y = -1
z = z + 1
end
local temp = generate_biomed_points(vector_add(sector,{x=x,y=y,z=z})
,seed,layer)
for i,v in ipairs(temp) do
points[index] = v
index = index + 1
end
x = x + 1
end
else
for i=1,9 do
if x > 1 then
x = -1
z = z + 1
end
local temp = generate_biomed_points(vector_add(sector,{x=x,y=0,z=z})
,seed,layer)
for i,v in ipairs(temp) do
points[index] = v
index = index + 1
end
x = x + 1
end
end
return find_closest(pos,points,layer.get_dist_fast)
end
vcnlib.get_node_biome = get_node_biome
--Simple biome map implimentation
--requires scaling to perform usably well
local get_biome_map_3d_flat = function(minp,maxp,layer,seed,byot)
local ret = byot or {}
local nixyz = 1
local table_size = ((maxp.z - minp.z) + 1)*((maxp.y - minp.y) + 1)
*((maxp.x - minp.x) + 1)
local x,y,z = minp.x,minp.y,minp.z
for nixyz=1,table_size do
if x > maxp.x then
x = minp.x
y = y + 1
end
if y > maxp.y then
y = minp.y
z = z + 1
end
ret[nixyz] = get_node_biome({x=x,y=y,z=z},seed,layer)
x = x + 1
end
return ret
end
vcnlib.get_biome_map_3d_simple = get_biome_map_3d_flat
--Simple 2d biome map implimentation
--Functions usably without scaling - have not tested against the experimental
--function, should be slower though
local get_biome_map_2d_flat = function(minp,maxp,layer,seed,byot)
local ret = byot or {}
local nixz = 1
for z=minp.z,maxp.z do
for x=minp.x,maxp.x do
ret[nixz] = get_node_biome({x=x,y=y,z=z},seed,layer)
nixz = nixz + 1
end
end
return ret
end
vcnlib.get_biome_map_2d_simple = get_biome_map_2d_flat
--This function can be used to scale any compliant 2d map generator
--This adds an extra overhead - but this is negligable
local scale_2d_map_flat = function(minp,maxp,layer,seed,map_gen,byot,scale_byot)
local minp,rmin = minp,minp
local maxp,rmax = maxp,maxp
if layer.scale then
minp = {x=floor(minp.x/scale),y=0,z=floor(minp.z/scale)}
maxp = {x=floor(maxp.x/scale),y=0,z=floor(maxp.z/scale)}
end
local ret
if layer.scale then
ret = scale_byot or {}
else
ret = byot or {}
end
ret = map_gen(minp,maxp,layer,seed,map_gen,ret)
if layer.scale then
local nixz = 1
local scalxz = 1
local scalsidx = abs(maxp.x - minp.x) + 1
local sx,sz,ix = 0,0,1
local newret = byot or {}
for z=rmin.z,rmax.z do
sx = 0
for x=rmin.x,rmax.x do
newret[nixz] = ret[scalxz]
nixz = nixz + 1
sx = sx + 1
if sx == scale then
scalxz = scalxz + 1
sx = 0
end
end
sz = sz + 1
if sz ~= scale then
scalxz = ix
else
scalxz = ix + scalsidx
ix = scalxz
sz = 0
end
end
ret = newret
end
end
--This function can be used to scale any compliant 3d map generator
--This adds an extra overhead - but this is negligable
local scale_3d_map_flat = function(minp,maxp,layer,seed,map_gen,byot,scale_byot)
local scale = layer.scale
local minp,rmin = minp,minp
local maxp,rmax = maxp,maxp
if layer.scale then
minp = {x=floor(minp.x/scale),y=floor(minp.y/scale)
,z=floor(minp.z/scale)}
--Replace def_table with map object
maxp = {x=floor(maxp.x/scale),y=floor(maxp.y/scale)
,z=floor(maxp.z/scale)}
end
local ret
if layer.scale then
ret = scale_byot or {}
else
ret = byot or {}
end
ret = map_gen(minp,maxp,layer,seed,ret)
if scale then
local nixyz = 1
local scalxyz = 1
local scalsidx = abs(maxp.x - minp.x) + 1
local scalsidy = abs(maxp.y - minp.y) + 1
local sx,sy,sz,ix,iy = 0,0,0,1,1
local table_size = ((rmax.z - rmin.z) + 1)*((rmax.y - rmin.y) + 1)
*((rmax.x - rmin.x) + 1)
local x,y,z = rmin.x,rmin.y,rmin.z
local newret = byot or {}
for z=rmin.z,rmax.z do
sy = 0
for y=rmin.y,rmax.y do
sx = 0
for x=rmin.x,rmax.x do
newret[nixyz] = ret[scalxyz]
nixyz = nixyz + 1
sx = sx + 1
if sx == scale then
scalxyz = scalxyz + 1
sx = 0
end
end
sy = sy + 1
if sy ~= scale then
scalxyz = ix
else
scalxyz = ix + scalsidx
ix = scalxyz
sy = 0
end
end
sz = sz + 1
if sz ~= scale then
scalxyz = iy
ix = iy
else
sz = 0
scalxyz = iy + scalsidy*scalsidx
iy = scalxyz
ix = iy
end
end
ret = newret
end
return ret
end
local shared_scale_byot = {}
--This is a single function which can be called to produce a biomemap
--for any layer type
--Attempts to choose the most optimal type for a given layer
--All scale code is condtional, so is safe to add to any mapgen
vcnlib.get_biome_map_flat = function(minp,maxp,layer,seed,byot)
local scale_byot = nil
if byot then
scale_byot = shared_scale_byot
end
if not layer.maps_init then
init_maps(layer)
end
if layer.dimensions == 3 then
local map_gen = nil
if layer.blocksize then
map_gen = get_biome_map_3d_experimental
else
map_gen = get_biome_map_3d_flat
end
return scale_3d_map_flat(minp,maxp,layer,seed,map_gen,byot,scale_byot)
else
local map_gen = nil
if layer.blocksize then
map_gen = get_biome_map_2d_experimental
else
map_gen = get_biome_map_2d_flat
end
return scale_2d_map_flat(minp,maxp,layer,seed,map_gen,byot,scale_byot)
end
end
vcnlib.new_layer = function(def)
local name = def.name
if vcnlib.layers[name] then
return
end
--Register layer into global table
vcnlib.layers[name] = def
local layer = vcnlib.layers[name]
--Default seed offset, to avoid errors layer where it is required
layer.seed_offset = layer.seed_offset or 0
--Number indexed table of biome names
layer.biomes = {}
--Key indexed table of biomes - indexed by biome.name
layer.biome_defs ={}
layer.biome_number = 0
--Layer object member functions
layer.get_biome_list = function(self,to_get)
return self.biomes
end
layer.add_biome = function(self,biome_def)
table.insert(self.biomes,biome_def.name)
table.insert(self.biome_defs,biome_def)
self.biome_number = self.biome_number + 1
end
--setup geometry function
layer.dist = vcnlib.geometry[layer.geometry]
if layer.dimensions == 3 then
layer.get_dist = layer.dist._3d
layer.get_dist_fast = layer.dist._3d_fast or layer.get_dist
else
layer.get_dist = layer.dist._2d
layer.get_dist_fast = layer.dist._2d_fast or layer.get_dist
end
--variable to track wether the noise maps have been initialised
if layer.biome_maps then
layer.maps_init = false
else
layer.maps_init = true
end
--setup layer cache to chache generated points
layer.cache = setmetatable({},vcnlib.meta_cache)
return layer
end
--for mods which are using a pre-defined biome layer
vcnlib.get_layer = function(to_get)
return vcnlib.layers[to_get]
end
vcnlib.meta_cache = {
__mode = "v",
}
--dofile(minetest.get_modpath("vcnlib").."/testtools.lua")
--dofile(minetest.get_modpath("vcnlib").."/test_layer.lua")

51
legacy.lua Normal file
View File

@ -0,0 +1,51 @@
--[[
--This file is inteded for placing unused code which may be useful
--for later work.
--
--This file will not be maintained in any way, other than having functions
--added and removed.
--
--]]
--intended for optimisation, will later be used for cubic noise instead
--[[
local solidblockfiller_2d = function(blockvalue,blocksize,table,tablesize,blockstart)
local tableit = blockstart
local zbuf = tablesize.x - blocksize.x
local x,z = 1,1
local blocklength = blocksize.x*blocksize.z
for i=1,blocklength do
if x > blocksize.x then
x = 1
z = z + 1
tableit = tableit + zbuf
end
table[tableit] = blockvalue
tableit = tableit + 1
x = x + 1
end
end
--for 2d use (x,y) rather than (x,0,z)
local solidblockfiller = function(blockvalue,blocksize,table,tablesize,blockstart)
local tableit = blockstart
local ybuf,zbuf = tablesize.x - blocksize.x,(tablesize.y - blocksize.y)*tablesize.x
local x,y,z = 1,1,1
local blocklength = blocksize.x*blocksize.y*(blocksize.z or 1)
for i=1,blocklength do
if x > blocksize.x then
x = 1
y = y + 1
tableit = tableit + ybuf
end
if y > blocksize.y then
y = 1
z = z + 1
tableit = tableit + zbuf
end
table[tableit] = blockvalue
tableit = tableit + 1
x = x + 1
end
end
--]]

21
license.txt Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 qwertymine3
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

125
maps.lua Normal file
View File

@ -0,0 +1,125 @@
--This file contains a list of simple custom maps
--These are to replace the old custom map model, and for optimisation
vcnlib.maps = {}
local maps = vcnlib.maps
--Height Maps
local get_height = function(pos)
return pos.y
end
local scale = function(value,scale)
return value*scale
end
local centre_height = function(value,centre)
return value-centre
end
local zero = function()
return 0
end
maps.height_map = {
get3d = function(self,pos)
return get_height(pos)
end,
get2d = zero,
construct = function()
return
end,
}
maps.scaled_height_map = {
get3d = function(self,pos)
return scale(pos.y,self.scale)
end,
get2d = zero,
construct = function(self,def)
self.scale = def.scale
return
end
}
maps.centred_height_map = {
get3d = function(self,pos)
return centre_height(pos.y,self.centre)
end,
get2d = zero,
construct = function(self,def)
self.centre = def.centre
return
end,
}
maps.scaled_centred_height_map = {
get3d = function(self,pos)
return scale(centre_height(pos.y,self.centre),self.scale)
end,
get2d = zero,
construct = function(self,def)
self.centre = def.centre
self.scale = def.scale
return
end,
}
--Distance functions
maps.centred_distance = {
get3d = function(self,pos)
return self.get_dist(self.centre,pos)
end,
get2d = function(self,pos)
return self.get_dist(self.centre,pos)
end,
construct = function(self,def)
self.dimensions = def.dimensions
self.geometry = def.geometry
self.centre = def.centre or {x=0,y=0,z=0}
self.get_dist = vcnlib.get_distance_function(self.geometry
,self.dimensions)
end,
}
maps.scaled_centred_distance = {
get3d = function(self,pos)
return scale(self.get_dist(self.centre,pos),self.scale)
end,
get2d = function(self,pos)
return scale(self.get_dist(self.centre,pos),self.scale)
end,
construct = function(self,def)
self.dimensions = def.dimensions
self.geometry = def.geometry
self.centre = def.centre or {x=0,y=0,z=0}
self.scale = def.scale
self.get_dist = vcnlib.get_distance_function(self.geometry
,self.dimensions)
end,
}
local get_map_object = function(map_def)
local object = {}
--Get the map type, and fail if none exists
local noise_map = maps[map_def.map_type]
--Choose function to load based on dimensions given
if map_def.dimensions == 3 then
object.get_noise = noise_map.get3d
else
object.get_noise = noise_map.get2d
end
--Use the map constructor to initialise
noise_map.construct(object,map_def)
return object
end
vcnlib.get_map_object = get_map_object
local register_map = function(map_def)
if not vcnlib.maps[map_def.name]
and map_def.get3d
and map_def.get2d
and map_def.construct then
vcnlib.maps[map_def.name] = map_def
end
end
vcnlib.register_map = register_map

118
test_layer.lua Normal file
View File

@ -0,0 +1,118 @@
local heatmap = {
map_type = "perlin",
dimensions = 3,
flags = nil,
lacunarity = 2,
octaves = 3,
offset = 50,
persistence = 0.5,
scale = 10,
seeddiff = 5349,
spread = {x=10,y=10,z=10},
}
local wetmap = {
--These values are added for vcnlib
--This identifies the type of map
map_type = "perlin",
--This identifies the number of dimensions it can be generated in
--This is mainly to be able to use a 2d map in a 3d noise map
dimensions = 2,
--These are minetest Perlin noise flags
flags = nil,
lacunarity = 2,
octaves = 3,
--average temp
offset = 50,
persistence = 0.5,
--plus or mius value
scale = 10,
seeddiff = 842,
spread = {x=10,y=10,z=10},
}
vcnlib.new_layer{
--name of the layer, used to get a copy of it later
name = "test",
--a number added to the world seed to amke different noises
seed_offset = 5,
--number of dimensions the noise changes over
dimensions = 3,
--scale to multiply the noise by(for performace)
--if not a factor of 80, there may be some artifacting at the edge
--of voxel manip blocks
scale = 5,
--This activates a more efficient algorithm which generates the map in
--blocks
--This sets the size of the blocks that it generates, performance
--improves with size only for smaller sizes: 1^3 < small > 80^3
blocksize = {x=5,y=5,z=5},
--This is the distribution of how many points are generated in each
--sector
--The index is the number of points - these MUST be continuous
--The number value is the minimum random number required for that value
--to be chosen
point_distribution = {
random_max = 20,
random_min = 1,
[1] = 1,
--This is an example of how to 'skip' a value - 2 is skipped
[2] = 20,
[3] = 20,
},
--side lengths for sectors (approx size for one biome)
sector_lengths = {x=5,y=5,z=5,},
--how biomes are chosen
biome_types = {
[1] = "multi-tolerance-map",
[2] = "multi-map",
[3] = "random",
[4] = "fail"
},
--perlin parameters for the heatmap and humidity map
biome_maps = {
--multimap maps
[1] = heatmap,
[2] = wetmap,
},
--tolerance levels for each biome map within which biomes are
--chosen at random
tolerance = {
--multimap tolerances
[1] = 10,
[2] = 10,
},
--how distance from the centre of a biome is judged
--changes he shape of generated biomes
geometry = "manhattan",
}
local test = vcnlib.get_layer("test")
test:add_biome{
--name of biome
name = "bland",
--Values for numbered noisemaps
--heat for multi
[1] = 40,
--humidity for multi
[2] = 40,
}
test:add_biome{
name = "boring",
[1] = 50,
[2] = 40,
}
test:add_biome{
name = "drab",
[1] = 50,
[2] = 40,
}
test:add_biome{
name = "dull",
[1] = 60,
[2] = 60,
}

26
testtools.lua Normal file
View File

@ -0,0 +1,26 @@
local seed = minetest.get_mapgen_params().seed
minetest.register_craftitem("vcnlib:biome_wand", {
description = "Biome Wand",
inventory_image = "farming_tool_diamondhoe.png",
on_place = function(itemstack, placer, pointed_thing)
--test_biomed_points(pointed_thing.above)
--minetest.chat_send_all((vcnlib.test))
--minetest.chat_send_all(vcnlib.pos_to_sector(pointed_thing.above,vcnlib.test).x)
local pos = pointed_thing.above
local scale = vcnlib.layers.test.scale
if scale then
minetest.chat_send_all(vcnlib.get_node_biome(({x=math.floor(pos.x/scale),y=math.floor(pos.y/scale),z=math.floor(pos.z/scale)}),seed,vcnlib.layers.test))
else
minetest.chat_send_all(vcnlib.get_node_biome(pos,seed,vcnlib.layers.test))
end
end,
})
minetest.register_craft({
output = "vcnlib:biome_wand",
recipe = {
{"default:diamond","default:diamond","default:diamond"},
{"default:diamond","default:stick", "default:diamond"},
{"default:diamond","default:stick", "default:diamond"},
},
})