Ground Content Conflict #1395

Open
opened 2021-03-27 00:29:35 +01:00 by kay27 · 22 comments
Contributor

Maybe it's mostly Minetest issue, https://github.com/minetest/minetest/issues/11125

Mapgen works using 'chunk in a shell' feature, generating map chunks of 5*5*5 blocks with additional block-sized layer around the chunk to make result smooth.

So in fact mapgen works in 7*7*7 cubes.

Outer layer can overwrite the content of neighbour map chunks!

Mostly it happens with nodes with .is_ground_content = true - it means building matherial for the mapgen.

Worst example is when some map block of 16*16*16 nodes located at a corner of 5*5*5 chunk - it means after its generation it can be overwritten 7 times!

7 times, Carl! I did my best to illustrate the problem, my painting isn't complete but hope will help to realize what's going on:

image

Moreover, my logs show me that air nodes are ground content too. Surprisingly. I'd like to be wrong.

We widely use air nodes in many schematics. We use schematics in register_on_generated callbacks. That's why these schematics need additional steps to anchor them, make them kinda 'mapgen-resistant', LOL.

I don't see clear way to resolve this. I endlessly patch the code but it starts to go too far. I fixed really really many things but it causes new bugs and slowdowns.

What I've tried: placement after the delay, emerge neighbour areas, re-emerge current areas, increase processing areas to 7x7x7 and decrease back to 5x5x5. What would work definitely - reduce the area to 3x3x3 blocks within 5x5x5 chunks, but it would mean the biggest part of the world will be just clean, pure Minetest game.

Let me introduce temporary new label ("ground content conflict") to mark these problems.

Maybe it's mostly Minetest issue, https://github.com/minetest/minetest/issues/11125 Mapgen works using 'chunk in a shell' feature, generating map chunks of 5\*5\*5 blocks with additional block-sized layer around the chunk to make result smooth. So in fact mapgen works in 7\*7\*7 cubes. Outer layer can overwrite the content of neighbour map chunks! Mostly it happens with nodes with ```.is_ground_content = true``` - it means building matherial for the mapgen. Worst example is when some map block of 16\*16\*16 nodes located at a corner of 5\*5\*5 chunk - it means after its generation it can be overwritten 7 times! 7 times, Carl! I did my best to illustrate the problem, my painting isn't complete but hope will help to realize what's going on: ![image](/attachments/22c2ee6f-8b60-4691-b30a-4bb99ff49ecc) Moreover, my logs show me that air nodes are ground content too. Surprisingly. I'd like to be wrong. We widely use air nodes in many schematics. We use schematics in ```register_on_generated``` callbacks. That's why these schematics need additional steps to anchor them, make them kinda 'mapgen-resistant', LOL. I don't see clear way to resolve this. I endlessly patch the code but it starts to go too far. I fixed really really many things but it causes new bugs and slowdowns. What I've tried: placement after the delay, emerge neighbour areas, re-emerge current areas, increase processing areas to 7x7x7 and decrease back to 5x5x5. What would work definitely - reduce the area to 3x3x3 blocks within 5x5x5 chunks, but it would mean the biggest part of the world will be just clean, pure Minetest game. Let me introduce temporary new label (_"ground content conflict"_) to mark these problems.
kay27 added the
ground content conflict
label 2021-03-27 00:29:35 +01:00
kay27 added the
mapgen
#P3: elevated
labels 2021-03-27 00:31:18 +01:00
Author
Contributor

If we require emerge of adjacent areas, it's like a chain reaction - they should require emerging next ones and mapgen never stops. So it's wrong way.
If we delay placing structures for some time - adjacent blocks might not be generated in this amount of time.
If we place schematics in shell layer ourselves - we can occasionally replace them ourselves but it doesn't help to protect them from the mapgen.
Etc...

But there is a good condition - when you come really near to some area - all chunks around generate entirely. And in a theory we can track when the generation process is finished.

So maybe I've got an algorithm:

  1. Enumerate all the chunks and store the data shows us which of them generated.
  2. Place schematics only when we sure - there will no any further modifications, and here is the check, formally:
  • agree that the biggest schematic we can place is 40x40x40 (chunk_size x block_size / 2);
  • determite to which half of chunk target place belongs, separately for all three coordinate axes;
  • if it is within -20...+20 from the middle - don't do additional checks;
  • if less than -20 - delay placement, wait for previous chunk;
  • if more than +20 - delay placement, wait for next chunk;
  • if we implement this for all three axes in a loop, corner neighbours should be processed as well;
  • if we use coroutines, they might stop and continue when all conditions will be met;
  • but we should flush the data to mod storage not to lose structures on server restart.

What guys you think about it?

If we require emerge of adjacent areas, it's like a chain reaction - they should require emerging next ones and mapgen never stops. So it's wrong way. If we delay placing structures for some time - adjacent blocks might not be generated in this amount of time. If we place schematics in shell layer ourselves - we can occasionally replace them ourselves but it doesn't help to protect them from the mapgen. Etc... But there is a good condition - when you come really near to some area - all chunks around generate entirely. And in a theory we can track when the generation process is finished. So maybe I've got an algorithm: 1. Enumerate all the chunks and store the data shows us which of them generated. 2. Place schematics only when we sure - there will no any further modifications, and here is the check, formally: + agree that the biggest schematic we can place is 40x40x40 (chunk_size x block_size / 2); + determite to which half of chunk target place belongs, separately for all three coordinate axes; + if it is within -20...+20 from the middle - don't do additional checks; + if less than -20 - delay placement, wait for previous chunk; + if more than +20 - delay placement, wait for next chunk; + if we implement this for all three axes in a loop, corner neighbours should be processed as well; + if we use coroutines, they might stop and continue when all conditions will be met; + but we should flush the data to mod storage not to lose structures on server restart. What guys you think about it?
Author
Contributor
mcl_vars.max_block_generate_distance = math.max(1, tonumber(minetest.get_mapgen_setting("max_block_generate_distance")) or 10)

-- mcl_vars.max_block_generate_distance = 10

-- 10 blocks = 160 nodes
-- (defined in minetest/builtin/settingtypes.txt)

This is why waiting for some seconds (like this in Settlements mod) fixes some central chunks, but doesn't fix next chunks where no players nearby.

```lua mcl_vars.max_block_generate_distance = math.max(1, tonumber(minetest.get_mapgen_setting("max_block_generate_distance")) or 10) -- mcl_vars.max_block_generate_distance = 10 -- 10 blocks = 160 nodes -- (defined in minetest/builtin/settingtypes.txt) ``` This is why waiting for some seconds (like [this in Settlements mod](https://gitlab.com/Rochambeau/settlements/-/blob/master/init.lua#L111)) fixes some central chunks, but doesn't fix next chunks where no players nearby.
Author
Contributor

Probably we can patch only place_schematics, set_node and something alike - basic things used by MCL2 mapgen:

  • Serialize a structure and split into blocks.

  • Then wait for adjacent chunks to be generated, for blocks in outer layer of chunk.


I just thought how much correctly it would be to use voxel manipulator to get generation status of such blocks... There are at least two ways to check adjacent chunk status:

First can be slow if the chunk is far, second needs a storage, which can be broken/damaged occasionally.

But the chunk is near! If defaultly generation barrier is 10 blocks, and ground content check&save barrier is no more than 4 blocks, - using the first way seems to be correct for me . And we wouldn't need chunk generation status storage if so, at least currently. Just engine API.

Well, next good step would be figuring out some abstraction, suitable and working fast. Coroutine would be so nice... if no need to flush structures unplaced still to mod storage, but we need it, because MC world should be deterministic

Probably we can patch only ```place_schematics```, ```set_node``` and something alike - basic things used by MCL2 mapgen: + Serialize a structure and split into blocks. + Then wait for adjacent chunks to be generated, for blocks in outer layer of chunk. ----------- I just thought how much correctly it would be to use voxel manipulator to get generation status of such blocks... There are at least two ways to check adjacent chunk status: + [use the Voxel Manipulator to read a single node](https://forum.minetest.net/viewtopic.php?p=325967#p325967) by Krock; + [mcl_mapgen_core.is_generated()](https://git.minetest.land/MineClone2/MineClone2/src/branch/master/mods/MAPGEN/mcl_mapgen_core/init.lua#L34) by me. First can be slow if the chunk is far, second needs a storage, which can be broken/damaged occasionally. But the chunk is near! If defaultly generation barrier is 10 blocks, and ground content check&save barrier is no more than 4 blocks, - using the first way seems to be correct for me . And we wouldn't need chunk generation status storage if so, at least currently. Just engine API. Well, next good step would be figuring out some abstraction, suitable and working fast. Coroutine would be so nice... if no need to flush structures unplaced still to mod storage, but we need it, because MC world should be deterministic
kay27 self-assigned this 2021-03-27 23:15:57 +01:00
ryvnf was assigned by kay27 2021-03-27 23:16:03 +01:00
Wuzzy was assigned by kay27 2021-03-27 23:16:09 +01:00
LizzyFleckenstein03 was assigned by kay27 2021-03-27 23:16:16 +01:00
kay27 added this to the 0.72.0 milestone 2021-03-27 23:16:28 +01:00
Author
Contributor

Hi, I've assigned you all just in case, mostly because I'm pretty sure: you can check my investigations and give really good advices which I would appreciate so much

Hi, I've assigned you all just in case, mostly because I'm pretty sure: you can check my investigations and give really good advices which I would appreciate so much
Member

even wuzzy?

even wuzzy?
epCode was assigned by kay27 2021-03-27 23:32:01 +01:00
tacotexmex was assigned by kay27 2021-03-27 23:32:49 +01:00
Rootyjr was assigned by kay27 2021-03-27 23:32:49 +01:00
aligator was assigned by kay27 2021-03-27 23:32:49 +01:00
AFCMS was assigned by kay27 2021-03-27 23:32:49 +01:00
kneekoo was assigned by kay27 2021-03-27 23:32:49 +01:00
MysticTempest was assigned by kay27 2021-03-27 23:32:49 +01:00
bzoss was assigned by kay27 2021-03-27 23:32:49 +01:00
Contributor

@kay27 This seems to involve way more mapgen stuff than I know (which is close to nothing), so if you need help to test something specific, let me know. :)

@kay27 This seems to involve way more mapgen stuff than I know (which is close to nothing), so if you need help to test something specific, let me know. :)
Contributor

How does this affect gameplay?

Why have existing mapgen issues been labelled as "ground content conflict"? How is this related to those?

I am quite confused with all of this.

How does this affect gameplay? Why have existing mapgen issues been labelled as "ground content conflict"? How is this related to those? I am quite confused with all of this.
Author
Contributor

@kay27 This seems to involve way more mapgen stuff than I know (which is close to nothing), so if you need help to test something specific, let me know. :)

probably you mean finished code?

i'm continuously doing so many tests myself so a bit confused which one would be at least fun for you, so this is very basic one (zipped)
you may unpack it to ./games, run 'Generators' game with 'carpathian' seed 123456789, all checkboxes set,
run /grantme all and fly below water level to see these beautiful pictures we don't expect to meet here (because we ordered fresh air nodes only)...

image

and this is expected (!) for Paramat, and this is because of Sokomine places his buildings repeatingly up to 8 times...

there are might be lots of ways to take it into account and wrap around it, we just need one fast and stable

> @kay27 This seems to involve way more mapgen stuff than I know (which is close to nothing), so if you need help to test something specific, let me know. :) probably you mean finished code? i'm continuously doing so many tests myself so a bit confused which one would be at least fun for you, so this is very basic one (zipped) you may unpack it to ./games, run 'Generators' game with 'carpathian' seed 123456789, all checkboxes set, run ```/grantme all``` and fly below water level to see these beautiful pictures we don't expect to meet here (because we ordered fresh air nodes only)... ![image](/attachments/da7c158c-6b0c-4587-9df0-108049a15362) and this is __expected__ (!) for Paramat, and this is because of Sokomine places his buildings repeatingly up to 8 times... there are might be lots of ways to take it into account and wrap around it, we just need one fast and stable
Author
Contributor

How does this affect gameplay?

it doesn't, just breaks our structures by cavegen code

Why have existing mapgen issues been labelled as "ground content conflict"?

because now i know the reason of them really well, and it's on the diagram in the first message

if we place regular nodes instead of marked as ground content, there are no problem absolutely :)

so the first i tried is just put alternative air to the schematics:

minetest.register_node("generators:good_air", {
	is_ground_content = false, -- seems doesn't give an effect because it's just not a mapgen alias, unknown to mapgen
	drawtype = "airlike",
	sunlight_propagates = true,
	walkable = false,
	pointable = false,
	diggable = false,
	floodable = true,
})

and it works - cavegen doesnt touch these nodes when we use them instead of the air

but they behave not like air nodes exactly, i'v seen little differences...

may be we can polish it somehow to remove the differences? or better implement what i suggested a little above?

it affects many things we generate in the real time with engine mapgen simultaneously, that's why elevated priority
map chunks overwrite each other - that's why it's a conflict of mapgen (for the engine - it's okay more likely)
etc
please don't get the assignment too serious
it will be fixed anyway somehow
your thoughts just might be very opportune

> How does this affect gameplay? it doesn't, just breaks our structures by cavegen code > Why have existing mapgen issues been labelled as "ground content conflict"? because now i know the reason of them really well, and it's on the diagram in the first message if we place regular nodes instead of marked as ground content, there are no problem absolutely :) so the first i tried is just put alternative air to the schematics: ```lua minetest.register_node("generators:good_air", { is_ground_content = false, -- seems doesn't give an effect because it's just not a mapgen alias, unknown to mapgen drawtype = "airlike", sunlight_propagates = true, walkable = false, pointable = false, diggable = false, floodable = true, }) ``` and it works - cavegen doesnt touch these nodes when we use them instead of the air but they behave not like air nodes exactly, i'v seen little differences... may be we can polish it somehow to remove the differences? or better implement what i suggested a little above? it affects many things we generate in the real time with engine mapgen simultaneously, that's why elevated priority map chunks overwrite each other - that's why it's a conflict of mapgen (for the engine - it's okay more likely) etc please don't get the assignment too serious it will be fixed anyway somehow your thoughts just might be very opportune
ryvnf was unassigned by kay27 2021-03-28 16:16:30 +02:00
aligator was unassigned by kay27 2021-03-28 16:16:31 +02:00
bzoss was unassigned by kay27 2021-03-28 16:16:31 +02:00
MysticTempest was unassigned by kay27 2021-03-28 16:16:31 +02:00
kneekoo was unassigned by kay27 2021-03-28 16:16:31 +02:00
Rootyjr was unassigned by kay27 2021-03-28 16:16:31 +02:00
Wuzzy was unassigned by kay27 2021-03-28 16:16:31 +02:00
tacotexmex was unassigned by kay27 2021-03-28 16:16:31 +02:00
LizzyFleckenstein03 was unassigned by kay27 2021-03-28 16:16:31 +02:00
epCode was unassigned by kay27 2021-03-28 16:16:31 +02:00
AFCMS was unassigned by kay27 2021-03-28 16:16:50 +02:00
Author
Contributor

What if I just try to optimize near-chunk-dependency function like we optimize digital machines in high schools... have no better ideas still... of course trivial way is 6 nested loops which I don't like but maybe better still start from it because it can be more clear

There are chunks on the diagram, 5 pictures from left to right are the layers, numbers in blocks (cells) are how many adjacent blocks should be generated to be sure it's a good time to place our schematics

image

What if I just try to optimize near-chunk-dependency function like we optimize digital machines in high schools... have no better ideas still... of course trivial way is 6 nested loops which I don't like but maybe better still start from it because it can be more clear There are chunks on the diagram, 5 pictures from left to right are the layers, numbers in blocks (cells) are how many adjacent blocks should be generated to be sure it's a good time to place our schematics ![image](/attachments/abc3c00f-216c-40af-81d3-f98577b2e71f)
Author
Contributor

Oh, just not to forget, it might be useful too but doubtful :)

local needs_x_minus = block_x % 5 == 0
local needs_x_plus = block_x % 5 == 4
local needs_y_minus = block_y % 5 == 0
local needs_y_plus = block_y % 5 == 4
local needs_z_minus = block_z % 5 == 0
local needs_z_plus = block_z % 5 == 4
Oh, just not to forget, it might be useful too but doubtful :) ```lua local needs_x_minus = block_x % 5 == 0 local needs_x_plus = block_x % 5 == 4 local needs_y_minus = block_y % 5 == 0 local needs_y_plus = block_y % 5 == 4 local needs_z_minus = block_z % 5 == 0 local needs_z_plus = block_z % 5 == 4 ```
Author
Contributor

I've tried many ideas and algorithms and get a bit tired.
Now I think these 3x3x3 cubes are not so small to be honest
изображение
Maybe we should force placement schematics in these safe cubes and allow cavegen.cpp to overwrite other areas as many times as it wants.
But there are some problems too.
E. g. we need to place ocean monument:

  1. It is a bit bigger than 48x48x48 by design. Reduce it???
  2. Currently safe altitude ranges are from -16 up to 31 (and from -80 up to -33). Water level here is from -16 up to -1 - 16 nodes height, minue one to not replace water surface, 15 nodes are too small. Shift overworld layer down???
    Crazy ideas, I know
I've tried many ideas and algorithms and get a bit tired. Now I think these 3x3x3 cubes are not so small to be honest ![изображение](/attachments/47476531-a58e-49b6-820a-6f44e23c49ff) Maybe we should force placement schematics in these safe cubes and allow cavegen.cpp to overwrite other areas as many times as it wants. But there are some problems too. E. g. we need to place ocean monument: 1. It is a bit bigger than 48x48x48 by design. Reduce it??? 2. Currently safe altitude ranges are from -16 up to 31 (and from -80 up to -33). Water level here is from -16 up to -1 - 16 nodes height, minue one to not replace water surface, 15 nodes are too small. Shift overworld layer down??? Crazy ideas, I know
Author
Contributor

image

![image](/attachments/22ded90c-9218-43ea-8c2a-64fdb1b9f917)
348 KiB
Author
Contributor

Okay, I realized my problem.

I thought we might don't do lots of redundant job writing the same content of map blocks again and again up to 8 times. I did all my experiments based on this supposition.
But it has a problem: nodes in partially generated map block interact with adjacent blocks and can change them, and it would be too difficult for me to remove leftovers of such interactions. Like water or lava when they flow down.
So probably Sokomine uses the only way currently possible - write map block content again and again, 69ac3f2691/mapgen.lua (L849)

Okay, I realized my problem. I thought we might don't do lots of redundant job writing the same content of map blocks again and again up to 8 times. I did all my experiments based on this supposition. But it has a problem: nodes in partially generated map block interact with adjacent blocks and can change them, and it would be too difficult for me to remove leftovers of such interactions. Like water or lava when they flow down. So probably Sokomine uses the only way currently possible - write map block content again and again, https://github.com/Sokomine/mg_villages/blob/69ac3f2691e8896082afa8f87504e7ae54ff7071/mapgen.lua#L849
Author
Contributor

изображение
изображение
изображение
изображение

![изображение](/attachments/d65aca16-2125-4acf-b0ce-86f40f5c8266) ![изображение](/attachments/1cb09867-779d-41db-9a54-6e47fdf377e8) ![изображение](/attachments/d348fa05-9c8b-4f52-b26b-3304a3bffb87) ![изображение](/attachments/8d54446d-158b-46bb-8025-8aac7bea9cb5)
Author
Contributor

изображение

![изображение](/attachments/0a4dadb4-8a48-4d2f-ade6-1dfb48d1dcb4)
Author
Contributor

изображение

![изображение](/attachments/994b4e4c-74a8-43e6-b27d-ba2ffdf1f5e2)
Author
Contributor

I've done it :)

minetest.register_node("generators:stone", {
	tiles = {"stone.png"},
	is_ground_content = false,
})
minetest.register_node("generators:water", {
	tiles = {"water.png"},
	is_ground_content = false,
	light_source = 14,
})

minetest.register_alias("mapgen_stone", "generators:stone")
minetest.register_alias("mapgen_water_source", "generators:water")

local c_air = minetest.get_content_id("air")
local c_stone = minetest.get_content_id("generators:stone")

local lb = {} -- buffer

local function on_generated(manip, data, area, minp, maxp, emin, emax)
	local p1 = vector.new(minp)
	local p2 = vector.new(maxp)
	for x = p1.x, p2.x do for y = p1.y, p2.y do for z = p1.z, p2.z do
		local p_pos = area:index(x, y, z)
		data[p_pos] = c_air
	end end end
end

local BS = 16
local CS = 5
local CS_MINUS_1 = CS - 1
local offset = -2
local math_floor = math.floor
local blocks = {}
minetest.register_on_generated(function(minp, maxp, blockseed)
	minetest.log("action", "Generating chunk " .. minetest.pos_to_string(minp) .. " ... " .. minetest.pos_to_string(maxp))

	local x0, y0, z0 = minp.x, minp.y, minp.z
	local bx0, by0, bz0 = math_floor(x0/BS), math_floor(y0/BS), math_floor(z0/BS)

	local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
	local data = vm:get_data(lb)
	local area = VoxelArea:new({MinEdge=emin, MaxEdge=emax})

	local x1, y1, z1, x2, y2, z2 = emin.x, emin.y, emin.z, emax.x, emax.y, emax.z
	local x, y, z = x1, y1, z1 -- iterate 7x7x7 mapchunk, {x,y,z} - first node pos. of mapblock
	local bx, by, bz -- block coords (in blocs)
	local box, boy, boz -- block offsets in chunks (in blocks)
	while x < x2 do
		bx = math_floor(x/BS)
		local block_pos_offset_removed = bx - offset
		box = block_pos_offset_removed % CS
		if not blocks[bx] then blocks[bx]={} end
		local total_mapgen_block_writes_through_x = (box > 0 and box < CS_MINUS_1) and 4 or 8
		while y < y2 do
			by = math_floor(y/BS)
			block_pos_offset_removed = by - offset
			boy = block_pos_offset_removed % CS
			if not blocks[bx][by] then blocks[bx][by]={} end
			local total_mapgen_block_writes_through_y = (boy > 0 and boy < CS_MINUS_1) and math_floor(total_mapgen_block_writes_through_x / 2) or total_mapgen_block_writes_through_x
			while z < z2 do
				bz = math_floor(z/BS)
				block_pos_offset_removed = bz - offset
				boz = block_pos_offset_removed % CS
				local total_mapgen_block_writes = (boz > 0 and boz < CS_MINUS_1) and math_floor(total_mapgen_block_writes_through_y / 2) or total_mapgen_block_writes_through_y
				local current_mapgen_block_writes = blocks[bx][by][bz] and (blocks[bx][by][bz] + 1) or 1
				if current_mapgen_block_writes == total_mapgen_block_writes then
					-- this block shouldn't be overwritten anymore, no need to keep it in memory
					blocks[bx][by][bz] = nil

					on_generated(vm, data, area, {x=x,y=y,z=z}, {x=x+BS-1,y=y+BS-1,z=z+BS-1}, emin, emax)
				else
					blocks[bx][by][bz] = current_mapgen_block_writes
				end

				z = z + BS
			end
			if next(blocks[bx][by]) == nil then blocks[bx][by] = nil end
			z = z1
			y = y + BS
		end
		if next(blocks[bx]) == nil then blocks[bx] = nil end
		y = y1
		x = x + BS
	end

	vm:set_data(data)
	vm:calc_lighting(emin, emax)
	vm:write_to_map()
end)

Every block 16x16x16 writes only once with this code.
So it would be fast for mapgens.
The only minor problem - I see far blocks, like these, which weren't already passed through out 2nd-level callbacks:
изображение

But when I fly nearier - they pass as well.

Oh, and one more minor problem - BLOCKS less than CHUNKS. Blocks are 16x16x16. So I probably shall rewrite mapgen_core of MineClone2 according to this

I've done it :) ```lua minetest.register_node("generators:stone", { tiles = {"stone.png"}, is_ground_content = false, }) minetest.register_node("generators:water", { tiles = {"water.png"}, is_ground_content = false, light_source = 14, }) minetest.register_alias("mapgen_stone", "generators:stone") minetest.register_alias("mapgen_water_source", "generators:water") local c_air = minetest.get_content_id("air") local c_stone = minetest.get_content_id("generators:stone") local lb = {} -- buffer local function on_generated(manip, data, area, minp, maxp, emin, emax) local p1 = vector.new(minp) local p2 = vector.new(maxp) for x = p1.x, p2.x do for y = p1.y, p2.y do for z = p1.z, p2.z do local p_pos = area:index(x, y, z) data[p_pos] = c_air end end end end local BS = 16 local CS = 5 local CS_MINUS_1 = CS - 1 local offset = -2 local math_floor = math.floor local blocks = {} minetest.register_on_generated(function(minp, maxp, blockseed) minetest.log("action", "Generating chunk " .. minetest.pos_to_string(minp) .. " ... " .. minetest.pos_to_string(maxp)) local x0, y0, z0 = minp.x, minp.y, minp.z local bx0, by0, bz0 = math_floor(x0/BS), math_floor(y0/BS), math_floor(z0/BS) local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") local data = vm:get_data(lb) local area = VoxelArea:new({MinEdge=emin, MaxEdge=emax}) local x1, y1, z1, x2, y2, z2 = emin.x, emin.y, emin.z, emax.x, emax.y, emax.z local x, y, z = x1, y1, z1 -- iterate 7x7x7 mapchunk, {x,y,z} - first node pos. of mapblock local bx, by, bz -- block coords (in blocs) local box, boy, boz -- block offsets in chunks (in blocks) while x < x2 do bx = math_floor(x/BS) local block_pos_offset_removed = bx - offset box = block_pos_offset_removed % CS if not blocks[bx] then blocks[bx]={} end local total_mapgen_block_writes_through_x = (box > 0 and box < CS_MINUS_1) and 4 or 8 while y < y2 do by = math_floor(y/BS) block_pos_offset_removed = by - offset boy = block_pos_offset_removed % CS if not blocks[bx][by] then blocks[bx][by]={} end local total_mapgen_block_writes_through_y = (boy > 0 and boy < CS_MINUS_1) and math_floor(total_mapgen_block_writes_through_x / 2) or total_mapgen_block_writes_through_x while z < z2 do bz = math_floor(z/BS) block_pos_offset_removed = bz - offset boz = block_pos_offset_removed % CS local total_mapgen_block_writes = (boz > 0 and boz < CS_MINUS_1) and math_floor(total_mapgen_block_writes_through_y / 2) or total_mapgen_block_writes_through_y local current_mapgen_block_writes = blocks[bx][by][bz] and (blocks[bx][by][bz] + 1) or 1 if current_mapgen_block_writes == total_mapgen_block_writes then -- this block shouldn't be overwritten anymore, no need to keep it in memory blocks[bx][by][bz] = nil on_generated(vm, data, area, {x=x,y=y,z=z}, {x=x+BS-1,y=y+BS-1,z=z+BS-1}, emin, emax) else blocks[bx][by][bz] = current_mapgen_block_writes end z = z + BS end if next(blocks[bx][by]) == nil then blocks[bx][by] = nil end z = z1 y = y + BS end if next(blocks[bx]) == nil then blocks[bx] = nil end y = y1 x = x + BS end vm:set_data(data) vm:calc_lighting(emin, emax) vm:write_to_map() end) ``` Every block 16x16x16 writes only once with this code. So it would be fast for mapgens. The only minor problem - I see far blocks, like these, which weren't already passed through out 2nd-level callbacks: ![изображение](/attachments/595fa53e-be55-45b8-942a-d9b1fbe5e874) But when I fly nearier - they pass as well. Oh, and one more minor problem - BLOCKS less than CHUNKS. Blocks are 16x16x16. So I probably shall rewrite mapgen_core of MineClone2 according to this
kay27 added a new dependency 2021-04-22 17:15:24 +02:00
Member

Nice!

Nice!
Contributor

cube movie

![cube movie](https://assets.cdn.moviepilot.de/files/b914c28f6274e1befdc88542b1415bb554e2366f25f7530f81a732e8f276/fill/992/477/Cube_Reboot_Remake_Cubed_Saman_Kesh.jpg)
kay27 added a new dependency 2021-04-25 01:48:29 +02:00
Author
Contributor

Okay. It seems to be resolved in mapgen branch with one minor issue:

There is no way to access mapgen objects FOR CHUNKS from safe callbacks (for blocks it is still possible) - need to invent something like:

  1. process unsafe callback - access objects to calculate and store whatever we need;
  2. process safe callback - place structures.

What is mapgen objects - they are arrays described here: https://github.com/minetest/minetest/blob/master/doc/lua_api.txt#L4177

  • voxelmanip
  • heightmap
  • biomemap
  • heatmap
  • humiditymap
  • gennotify

Well... I need further ideas :)

Probably it's still more likely the engine issue.

Here is the code of my safe block/chunk callbacks: f4a28cfab0/mods/CORE/mcl_mapgen/init.lua (L103)

Closing.

Okay. It seems to be resolved in ```mapgen``` branch with one minor issue: There is no way to access mapgen objects FOR CHUNKS from safe callbacks (for blocks it is still possible) - need to invent something like: 1) process unsafe callback - access objects to calculate and store whatever we need; 2) process safe callback - place structures. What is mapgen objects - they are arrays described here: https://github.com/minetest/minetest/blob/master/doc/lua_api.txt#L4177 + `voxelmanip` + `heightmap` + `biomemap` + `heatmap` + `humiditymap` + `gennotify` Well... I need further ideas :) Probably it's still more likely the engine issue. Here is the code of my safe block/chunk callbacks: https://git.minetest.land/MineClone2/MineClone2/src/commit/f4a28cfab0c686c9b750e0c0f53e287a8d7b667f/mods/CORE/mcl_mapgen/init.lua#L103 Closing.
kay27 closed this issue 2021-05-02 02:10:46 +02:00
Author
Contributor

reopening. it was closed in favor of one pr, then another, but they are not merged, so i guess better to have it open.

reopening. it was closed in favor of one pr, then another, but they are not merged, so i guess better to have it open.
kay27 reopened this issue 2022-04-21 01:19:29 +02:00
cora removed a dependency 2022-11-03 19:52:03 +01:00
ancientmarinerdev removed this from the 0.72.0 milestone 2023-01-10 22:39:35 +01:00
ancientmarinerdev added this to the 3 - Near future milestone 2023-02-04 03:43:50 +01:00
ancientmarinerdev removed the
#P3: elevated
label 2023-02-04 03:43:55 +01:00
ancientmarinerdev added the
#Review
label 2023-05-11 15:06:09 +02:00
ancientmarinerdev removed this from the 3 - Near future milestone 2023-05-11 15:06:13 +02:00
the-real-herowl added this to the Mapgen update project 2024-03-31 19:17:51 +02:00
Sign in to join this conversation.
No Milestone
No project
No Assignees
5 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Blocks
#1596 (Another) Portal bug
VoxeLibre/VoxeLibre
Reference: VoxeLibre/VoxeLibre#1395
No description provided.