firefox wrote:1. is it possible to generate biomes only in a set part of the map (e.g. north)?
2. is it possible to use different mapgen parameters in different regions of the map?
(e.g. more islands in the east, high mountains in the north, ect.)
firefox wrote:1. is it possible to generate biomes only in a set part of the map (e.g. north)?
2. is it possible to use different mapgen parameters in different regions of the map?
(e.g. more islands in the east, high mountains in the north, ect.)
firefox wrote:1. is it possible to generate biomes only in a set part of the map (e.g. north)?
Sane wrote:Hi there,
I like the l-system tree generation. So I am rolling the idea of adapting that system for map generation.
Writing an l-system parser should not be a problem.
The thing is that I do not have an idea how to make a structure extend over the edges of map generation blocks.
To get started I thougt I'd use the register_on_generated function.
Then somhow determine if that this block will contain seed point from which out an l-system structure would expand.
If so the parser would run and generate a neat set of coordinates and structures to build.
And at that point I (quite literally) hit a wall. How woud one go about to make that structure continue in the neighboring blocks. Problematic is that the neigbor might have already been generated (darn! what a mess).
And also there is a problen to solve with individual l-system overlapping.
Ideas anyone?
By the way, I've noticed that register_on_generated gets called several times for the same coordinates. That seems odd to me. Is that behaviour normal?
ArguablySane wrote:I've solved this problem before. Essentially you need to calculate where things will be spawning in neighbouring blocks and add the bits which intrude into the current block being generated.
The hard bit is that there's no easy way to get the seed for adjacent blocks. What I did was break the map up into my own virtual chunks which didn't have align with or be the same size as real 80x80x80 blocks. Each virtual chunk had a seed calculated from its x,y,z coordinates and the map seed.
ArguablySane wrote:When generating a block my mod automatically calculated which chunks overlapped ...
ArguablySane wrote:... It's a tiny bit harder if you want to include perlin noise in your generation code, ... I'm going to be tackling that particular problem in the next few days ...
ArguablySane wrote:... , so I might have some nice code to show you soon.
Sane wrote:I think that I'll keep a table with the structure's positions and check those within new block's on_generate. That might also solve the problem with overlapping. The simplest soulution could just be skipping the new structure, if it overlaps any part of a peviously generate one.
-- License: WTFPL
-- This code is free. Do whatever you want with it.
-- If you make something cool, don't forget to share.
-- Copyright law is absurd and should be ignored at every opportunity.
local map_seed = minetest.get_mapgen_params().seed
local cell_size = 160
local points_per_cell = 10
-- Scales the output of the PcgRandom object to be in the range 0-1.
-- NOTE: Will not work with PseudoRandom.
local function rand_float(prng)
return (prng:next()+2147483648)/4294967296
end
-- Rounds coordinates to an integer value
local function round_xyz(pos)
return {x=math.floor(pos.x+0.5), y=math.floor(pos.y+0.5), z=math.floor(pos.z+0.5)}
end
-- This function takes the position of a unit cell and returns a table of random points inside it
-- pos indicates the minimum corner of the cell in cell-coordinates (scaled such that a cell is a unit cube)
local function get_cell_points(pos)
-- Each cell gets its own seed
local prng = PcgRandom(minetest.hash_node_position(pos) + map_seed)
local points = {}
for i=1,points_per_cell do
local rx = rand_float(prng) -- A random number between zero and one.
local ry = rand_float(prng)
local rz = rand_float(prng)
local seed = prng:next() -- You can use this as a seed for generating random structures. It will be different for each one.
points[#points+1] = {x=pos.x+rx, y=pos.y+ry, z=pos.z+rz, s=seed}
end
return points
end
-- This function takes the min and max points in a mapgen block and returns a list of points which
-- lie inside cells either overlapping or adjacent to the mapgen block.
-- The list is guaranteed to contain all points which are no more than cell_size distance from the block's edge.
local function get_nearby_points(minp, maxp)
-- Scale it down to a coordinate system where a cell is a 1x1x1 cube.
min_scaled = {x=math.floor(minp.x/cell_size), y=math.floor(minp.y/cell_size), z=math.floor(minp.z/cell_size)}
max_scaled = {x=math.floor(maxp.x/cell_size), y=math.floor(maxp.y/cell_size), z=math.floor(maxp.z/cell_size)}
local points = {}
-- Iterate over all nearby cells
for z=min_scaled.z-1,max_scaled.z+1 do
for y=min_scaled.y-1,max_scaled.y+1 do
for x=min_scaled.x-1,max_scaled.x+1 do
-- Get the points in that cell and add them to the list
local cell_points = get_cell_points{x=x, y=y, z=z}
for i=1,#cell_points do
local p = cell_points[i]
-- Rescale back up to normal coordinates.
points[#points+1] = {x=p.x*cell_size, y=p.y*cell_size, z=p.z*cell_size, s=p.s}
end
end
end
end
return points
end
minetest.register_on_mapgen_init(function(mgparams)
if mgparams.mgname ~= "singlenode" then
minetest.set_mapgen_params({mgname="singlenode"})
end
end)
minetest.register_on_generated(function(minp, maxp, seed)
-- Get node ids
local air = minetest.get_content_id("air")
local grass = minetest.get_content_id("default:dirt_with_grass")
local dirt = minetest.get_content_id("default:dirt")
local stone = minetest.get_content_id("default:stone")
local wood = minetest.get_content_id("default:wood")
local t1 = os.clock()
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
local data = vm:get_data()
-- Fill the floor in with grass/dirt/stone first.
for z=minp.z,maxp.z,1 do
for y=minp.y,maxp.y,1 do
for x=minp.x,maxp.x,1 do
if y <= -5 then
data[area:index(x, y, z)] = stone
elseif y <= -2 then
data[area:index(x, y, z)] = dirt
elseif y <= -1 then
data[area:index(x, y, z)] = grass
end
end
end
end
local points = get_nearby_points(minp, maxp)
local r = 4
-- Iterate over the nearby points and generate 9x9x9 cubes of wood
for i=1,#points do
local p = round_xyz(points[i])
-- Include bounds checking so it doesn't write outside of the currently generating block.
-- This is EXTREMELY IMPORTANT. area:index(x,y,z) has no bounds checking, so it will do crazy things.
-- It took me far too long to track down that bug.
for z=math.max(minp.z,p.z-r),math.min(maxp.z,p.z+r) do
for y=math.max(minp.y,p.y-r),math.min(maxp.y,p.y+r) do
for x=math.max(minp.x,p.x-r),math.min(maxp.x,p.x+r) do
data[area:index(x, y, z)] = wood
end
end
end
end
-- Logging code to record how long it takes to generate a block
local t2 = os.clock()
local gen_time = math.ceil((t2 - t1) * 1000)
minetest.chat_send_all("chunk generated in "..gen_time.." ms")
minetest.log("action", minetest.pos_to_string(minp).." generated in "..gen_time.." ms")
vm:set_data(data)
vm:set_lighting({day=0, night=0})
vm:calc_lighting()
vm:write_to_map(data)
--vm:update_liquids()
end)
ArguablySane wrote:Sane wrote:I think that I'll keep a table with the structure's positions and check those within new block's on_generate. That might also solve the problem with overlapping. The simplest soulution could just be skipping the new structure, if it overlaps any part of a peviously generate one.
If you do it that way, you'll need to save the table in a file so it isn't lost when you shut down the server. It will also mean that mapgen will depend on the order blocks are generated. If you first approach an area from the East it might look different than if you approached it from the West.
ArguablySane wrote:I've knocked together a quick example of how I do it
. ...
Sane wrote:Very very cool!
local perlin_map = minetest.get_perlin_map(perlin_params, chulens):get3dMap_flat(minp)
local pn = minetest.get_perlin(perlin_params)
local value = pn:get2d(pos)
Users browsing this forum: No registered users and 13 guests