Mapgen Manual

User avatar
firefox
Member
 
Posts: 1185
Joined: Wed Jan 14, 2015 07:34
In-game: Red_Fox

Mapgen Manual

by firefox » Fri Aug 28, 2015 08:16

i once found a short manual on how to define biomes and mapgen parameters and what the different values do, but now i can't find it anymore.
does anybody know where to find it?

also i have some other mapgen questions:

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.)
 

User avatar
rubenwardy
Member
 
Posts: 4500
Joined: Tue Jun 12, 2012 18:11
GitHub: rubenwardy
IRC: rubenwardy
In-game: rubenwardy

Re: Mapgen Manual

by rubenwardy » Fri Aug 28, 2015 08:28

 

User avatar
ArguablySane
Member
 
Posts: 116
Joined: Sun Oct 12, 2014 21:29

Re: Mapgen Manual

by ArguablySane » Fri Aug 28, 2015 09:07

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.)

Yes, if you're using a lua mapgen.
What you want to do first is get each of those terrain types working as an individual mapgen on its own. Once you have them working separately, then put them together in the same file and blend them based on the x,z coordinates. Basically each terrain generator should produce a y value for given x,z coordinates, and you should take a weighted average of those y values.

You can also change the weighting of the average based on the value of another perlin noise function, so the distribution of terrain types is more random. For example, I've been writing a mapgen which has 5 different perlin noise maps. One of them is just the base terrain height which varies slowly over large distances, one is a very "hilly" heightmap, and one is big sweeping cliffs. The other two perlin noise maps act to modulate the scale of the hills and cliffs so some areas have lots of hills or lots of cliffs, while others are very flat.
Last edited by ArguablySane on Fri Aug 28, 2015 21:40, edited 2 times in total.
The above post and any ideas expressed therein are released to the public domain under a Creative Commons CC0 license.
 

paramat
Member
 
Posts: 2662
Joined: Sun Oct 28, 2012 00:05
GitHub: paramat

Re: Mapgen Manual

by paramat » Fri Aug 28, 2015 21:39

Jordach's manual linked to is out of date, best look at minetest_game/mods/default/mapgen.lua

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.)


Not with the biome API and mgv5/mgv7, only with a custom lua mapgen.

The biome API is only just stable so soon i need to write some documentation, and some explanation of noise parameters.
 

User avatar
firefox
Member
 
Posts: 1185
Joined: Wed Jan 14, 2015 07:34
In-game: Red_Fox

Re: Mapgen Manual

by firefox » Sat Aug 29, 2015 05:55

thank you all for your helpful replies.
if it can't be done with v5/7 then i will use a normal mapgen for now.
i don't think that i can write a new lua mapgen.

my design idea was to have a 3 realm world with underground biomes and skylands.
and as further motivation to move around the map i wanted to special biomes in set directions.
(the middle part of the map has taiga and some snow fields, but to find icebergs and glaciers as well as frozen trees you have to go far north.)
i think making special biomes rare would also encourage travelling.
 

User avatar
kaadmy
Member
 
Posts: 627
Joined: Thu Aug 27, 2015 23:07
GitHub: kaadmy
IRC: KaadmY
In-game: KaadmY kaadmy NeD

Re: Mapgen Manual

by kaadmy » Mon Aug 31, 2015 23:18

It would be nice to be able to change the mapgen noise params per biome, I haven't been able to figure out a way yet, and a lua mapgen would be slow.
Never paint white stripes on roads near Zebra crossings.
 

User avatar
kaadmy
Member
 
Posts: 627
Joined: Thu Aug 27, 2015 23:07
GitHub: kaadmy
IRC: KaadmY
In-game: KaadmY kaadmy NeD

Re: Mapgen Manual

by kaadmy » Mon Aug 31, 2015 23:23

It would be nice to be able to change the mapgen noise params per biome, I haven't been able to figure out a way yet, and a lua mapgen would be slow.
Never paint white stripes on roads near Zebra crossings.
 

paramat
Member
 
Posts: 2662
Joined: Sun Oct 28, 2012 00:05
GitHub: paramat

Re: Mapgen Manual

by paramat » Tue Sep 01, 2015 08:28

firefox wrote:1. is it possible to generate biomes only in a set part of the map (e.g. north)?

However you can locate biomes by altitude, each has y_min and y_max. So if you can get a core mapgen to generate stacked realms (this is intended for the future, mgv7 is nearly capable of this already) each realm can have it's own set of biomes.
 

User avatar
Sane
Member
 
Posts: 103
Joined: Tue Jun 17, 2014 09:31
GitHub: mt-sane
In-game: Sane

Re: Mapgen Manual

by Sane » Tue Sep 01, 2015 09:46

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?
Trying to stay me.
 

User avatar
ArguablySane
Member
 
Posts: 116
Joined: Sun Oct 12, 2014 21:29

Re: Mapgen Manual

by ArguablySane » Tue Sep 01, 2015 17:10

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?

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. When generating a block my mod automatically calculated which chunks overlapped with that block, and all the ones adjacent to those ones. For each chunk it generated random points where things (caves in this case) would be spawned, and used that information to work out what should go in the current block being generated.

It's a tiny bit harder if you want to include perlin noise in your generation code, but only because it's very easy to waste CPU cycles generating 27 times as much data for every block if you're not careful. I'm going to be tackling that particular problem in the next few days, so I might have some nice code to show you soon.
The above post and any ideas expressed therein are released to the public domain under a Creative Commons CC0 license.
 

User avatar
Sane
Member
 
Posts: 103
Joined: Tue Jun 17, 2014 09:31
GitHub: mt-sane
In-game: Sane

Re: Mapgen Manual

by Sane » Tue Sep 01, 2015 20:37

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.

Yes that's good. Seperating the block position from the generated structure's position sounds managable. Using a separately generated seed for the structure is also an good idea.

ArguablySane wrote:When generating a block my mod automatically calculated which chunks overlapped ...

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.

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 ...

Good luck with that.

ArguablySane wrote:... , so I might have some nice code to show you soon.

That'll be great.

Thanks a lot for the pointers. Kudos.
Trying to stay me.
 

User avatar
ArguablySane
Member
 
Posts: 116
Joined: Sun Oct 12, 2014 21:29

Re: Mapgen Manual

by ArguablySane » Tue Sep 01, 2015 21:43

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.

I've knocked together a quick example of how I do it. This code should work (fingers crossed) if you just save it as init.lua in a new mod. At the moment it just generates very boring wooden cubes in an infinite flat world, but you should be able to modify it to do whatever you need.
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
Code: Select all
-- 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)
The above post and any ideas expressed therein are released to the public domain under a Creative Commons CC0 license.
 

User avatar
Sane
Member
 
Posts: 103
Joined: Tue Jun 17, 2014 09:31
GitHub: mt-sane
In-game: Sane

Re: Mapgen Manual

by Sane » Wed Sep 02, 2015 17:34

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.

Yes, I'll have to keep in mind that i have to do stuff stateless. Didn't think about shutdown.

ArguablySane wrote:I've knocked together a quick example of how I do it
. ...

Very very cool!
Trying to stay me.
 

User avatar
ArguablySane
Member
 
Posts: 116
Joined: Sun Oct 12, 2014 21:29

Re: Mapgen Manual

by ArguablySane » Wed Sep 02, 2015 19:33

Sane wrote:Very very cool!

Thanks.

Also, just in case you were curious, I did a comparison of the two ways of generating perlin noise values:

Bulk generation (the normal way):
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
Code: Select all
local perlin_map = minetest.get_perlin_map(perlin_params, chulens):get3dMap_flat(minp)

Point generation:
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
Code: Select all
local pn = minetest.get_perlin(perlin_params)
local value = pn:get2d(pos)

It seems that point generation is consistently about 6 times slower at generating the same number of points as bulk generation.

Why this is relevant is that if you use perlin noise to generate the terrain height and then you want to use the terrain height to affect objects which overlap between chunks, then you don't actually need to generate all the terrain for adjacent chunks. If out-of-chunk objects query less than 1/6 of the points in adjacent chunks, then it's faster to just use the second method to get the terrain height (or any other perlin parameters) at those specific points. You only need to generate all of the terrain for the block you're currently generating.

EDIT: Also, it takes an extremely short amount of time to generate 2d perlin noise: approximately 0.2 ms per 80x80 block.
The above post and any ideas expressed therein are released to the public domain under a Creative Commons CC0 license.
 

User avatar
ArguablySane
Member
 
Posts: 116
Joined: Sun Oct 12, 2014 21:29

Re: Mapgen Manual

by ArguablySane » Fri Sep 04, 2015 00:01

EDIT: Disregard this. Turns out I was wrong, or at least not entirely right. I'll edit this post again when I've figured the problem out.
The above post and any ideas expressed therein are released to the public domain under a Creative Commons CC0 license.
 

Sokomine
Member
 
Posts: 2980
Joined: Sun Sep 09, 2012 17:31

Re: Mapgen Manual

by Sokomine » Fri Sep 04, 2015 15:18

I've hit similar problems with the villages. My approach is to store the village data - that is, the table that says which building goes where - in a file (as ArguablySane suggested here as well). That's necessary for other village-related things like beeing able to teleport to a particular village, or like showing a map of nearby villages.

In general, the key point with all mapgen things is to be able to reproduce exactly the same outcome whenever mapgen throws a block at you. At least for the same seed. Small things like plants may vary - nobody will notice. Having diffrent structures when loading the mapchunks in a diffrent order is a guarantee for trouble.

Also keep in mind that mapchunks come with a "shell" of 16 nodes in each direction when generated. That is for caves to be able to extend further. If you don't want cavegen griefing or mudflow causing unexpected dirt lines, you need to be able to reproduce those 16 nodes from the neighbouring mapchunk as well.
A list of my mods can be found here.
 

User avatar
Sane
Member
 
Posts: 103
Joined: Tue Jun 17, 2014 09:31
GitHub: mt-sane
In-game: Sane

Re: Mapgen Manual

by Sane » Sun Sep 20, 2015 15:36

This might be a bit offtopic but since I've spoken about it ...

I've published my LSystem.
It does not address any of of the mapgen problems. But it might be useful for generating mines, dungeons and so on.

Have fun y'all.
Trying to stay me.
 


Return to Minetest General

Who is online

Users browsing this forum: No registered users and 13 guests

cron