-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mapgen: "Unfinished" y-slices with num_emerge_threads > 1 #9357
Comments
You were warned: EDIT: Duplicate of #5618 |
Oh, somehow I missed that issue, thanks. Edit: This isn't exactly a crash though, more like a minor glitch 😉 In fact it's the only problem I encountered with multiple mapgen threads so far after running a private server for > 1 year. |
I had not noticed this bug before. This is probably due to how most mapgens 'overgenerate' terrain by 1 node above and below the currently generating mapchunk. |
This is not a duplicate of #5618 , although it is related, and the stone layer has appeared alongside the chopped trees in one screenshot. Reopening. |
See #5618 (comment) |
I made a simple game that shows the nodes produced by this bug as pink, it also marks mapchunk edges. Perhaps someone can find it useful for debugging this. https://codeberg.org/perfect_city_game_studio/mapgen_test Edit: replaced screenshot as it also contained a bug on my side. |
Played around with this a bit. This is stone being placed where it shouldn't be, so I just looked where I tried taking this "overgeneration" out, and it seems like it might fix this issue, but it completely messes up lighting. I'm not sure how "overgeneration" of +-1 Y is supposed to work, especially in a multithreaded context. I imagine in a singlethreaded context it might be fine due to only replacing ignore nodes. |
I'm pretty sure we've had the cutoff trees from #5618 with default settings in VoxeLibre... no weird stone layers though. We have a label for such weird issues, most of which may be manifestations of this issue: https://git.minetest.land/VoxeLibre/VoxeLibre/issues?q=&type=all&sort=&state=open&labels=211&milestone=0&project=0&assignee=0&poster=0 And the issue I mentioned specifically: https://git.minetest.land/VoxeLibre/VoxeLibre/issues/4369 We tried to look for possible causes in our code, but failed. |
@kno10 This is with |
Yes, |
I believe this happens because unfinished chunks write their data to chunks that had already been generated. |
Does it also occur when num_emerge_threads=1 sometimes? For example if you slowly ascending up to an ungeneread block. Of if you slowly descending to an ungenerated block? |
The problem is that two neighboring chunks (aka 5^3 blocks + border) could generate simultaneously.
v3s16 chunk_pos = getContainerPos(blockpos, 5);
int selected_queue =
(chunk_pos.X % 2) << 2 |
(chunk_pos.Y % 2) << 1 |
(chunk_pos.Z % 2) << 0;
To visualize which chunk member (aka block) goes in which queue.
|
It is surely possible to make the emerge code not emerge neighboring map chunks, but is that the correct fix? I somehow doubt it. |
I've just implemented it, and it runs almost as fast as before. The artifacts are completely gone. There needs to be a mechanism that stops neighboring chunks from generating simultaneously. And this way it works with almost no locking. An alternative would be to lock 26 neighboring chunks, per chunk that gets generated simultaneously. Each incoming block position needs to be tested if it is part of such chunk. And the thread needs to wait or redirect the position back into the queue and try another one. I've tried that as well, and it's worse than one thread. Or do you imagine something entirely different like simultaneous writing to the same location and then merging after the fact? |
I believe it could be a good solution to get around the locking issue. This is likely to improve the generation speed at large mapblock generation ranges where we can allow an 1 chunk gap in all directions. @cosin15 Would you please be so nice to provide a PR? That would allow us to perform benchmarks to check whether such change would make sense. |
As the overlap of map chunk generation is -- if I am not mistaken -- 16 nodes, and the error only every is one layer and only on the y axis -- doesn't this suggests it rather is a off-by-one in some if condition? But I haven't completely understood how overgeneration in Minetest works (and it's limits, #14437). It seems there are two kinds of overgeneration, one by a 16 node block, and the other by a single node on the y axis only (probably to determine what is a surface node and what is not?) |
It surely looks like that, but this does not account for the sliced trees. My solution only fixes the bug with the sliced trees, but it also prevents the other bug from coming to the surface. It is indeed not a fix for this particular issue. |
Well, I'd rather pick a workaround that works rather than a proper fix that never arrives (this issue is 5 years old). |
It is a workaround for the 'unfinished y-slices' as a side effect but a legit fix for the sliced trees. Because the locking mechanism that prevents neighboring chunks from generating simultaneously is not just broken, it appears to be absent to this day. |
Sure, a workaround is better than nothing. But if this means every map chunk writes 1 layer into the chunk above, that also means unnecessary IO right? |
I don't know if that's the case. I bet that the 1 layer-bug becomes malicious dead code, that is lurking in the shadows. |
Mapgen v7 overgenerates terrain y+-1, writes to the VM: |
|
Nevermind the lower part is in blocks, not in node coordinates. |
The code appears to overgenerate that stuff by 1 mapblock, yeah. I had that problem with voxel manipulators spawned for one whole chunk right after generation. It can run into a race condition with a neighboring chunk. In my case I tried changing soil from one thing to another but a neighboring chunk altered that change. This can be seen here: #13712 |
Disabling the overgeneration apparently causes lighting issues, but there are known lighting issues even as-is, which prompted for example creation of https://gitlab.com/sztest/szutilpack/-/tree/master/szutil_fixhack Maybe the proper way to fix this and other issues is to look in depth at how we do lighting, and how we could do it better? |
AFAIK this is what we're trying to do right now. |
That would be a really cool solution. I have some ideas for that:
|
This is a game-specific solution. There are Luanti games that don't have leaves/logs so modders would need to set priority themselves. What if the decoration is actually a tower? In my Luanti game I wrote a custom mapgen where overgeneration happens by mirroring movement of a "brush" for each map division unit and that movement is deterministic. In other words for structure/decoration placement you could just completely remove overgeneration (the shell of 1 mapblock) and simply spawn the structure twice (or more) for each mapchunk with due offset and just ignore nodes that poke out of each mapchunk. As long as structure placement is deterministic it works. EDIT: doing the above would actually increase the size limit for structures. In my game I generate 800x800 node "citychunks" and the brush mirroring (overgeneration) has a 200 node margin. Citychunks are generated together (with locking and all that stuff) so generating one involves generating all adjacent neighbors (including the "fake" overgeneration - mirroring generation of a structure for adjacent citychunks). |
Except that, as far as i can tell, most mapgens (including mpgv7) do write one layer of nodes into the next chunk, not only for trees. And that is probably one of the causes this problem here. |
Only if the structure placement is unconditional. This may work for your cities project, but will not work for many other cases. For example, cavegen might remove the place the tree was supposed to be placed. Without computing cavegen also in the upper chunk (and hence without recomputing almost the entire lower chunk twice!) you do not know if the tree placement below will even be possible. Or some other structure may collide and prevent the tree from spawning. Or for more complex structures, terraforming may need to happen to make the ground flat enough, which may slightly move the position suggested by randomness. |
I think the best would be if we had multiple tiers of chunk generation. If a chunk gets generated it is guaranteed that the neighboring chunks are on the same tier or higher. |
Sounds reasonable. I actually plan to solve placing buildings in my game this way: first generate roads, then place buildings randomly and finally connects the buildings with streets and roads. It creates a nice hierarchy and makes sure further steps have all the data needed.
Fair point. My mapgen actually does conditional placing right now and is going to do even more, but I use a top-down strategy (the layout is defined before doing any actual mapgen). It could still work though as long as each thread would be given the whole context. You'd need to communicate the threads with each other for that, which could slow down generation. As for your cave example I've seen trees and grass with nothing below them as a result of cavegen so the mapgen is still pretty blind to context as is right now. |
Minetest version
908e762
Bug has been around at least since 0.4.17
OS / Hardware
Operating system: Arch Linux
CPU: Intel(R) Core(TM) i5-3210M CPU @ 2.50GHz
Summary
When setting
num_emerge_threads
to a value greater than one (defaultchunksize
), the mapgen sometimes generates strange y-slices where biome-specific nodes, ores and caves are missing, and decorations extending into them seem to be cut off above.I've been able to reproduce this with several different mapgens (v7, valleys, carpathian) and map database backends (SQLite, PostgreSQL).
I am aware that using multiple emerge threads is considered somewhat experimental and advised against in the default config, but still have hope that someone with in-depth knowledge of the mapgen code (@paramat 😉) might be able to spot this one.
Steps to reproduce
Just start a game and fly around for a few minutes. The bug appears using the minimal game, but may be easier to spot in MTG because of the cut-off trees.
Above ground (valleys, minimal game):
Above ground (v7, MTG):
Above ground (valleys, MTG):
Caverns (valleys, MTG):
The slices always seem to appear at mapblock borders (see coordinates):
As far as I understand it, it always happens in (parts of) a mapchunk's topmost (Edit: or lowermost) y-slice.
When other mods try to place additional structures in an on_generated callback, they are cut off as well (in this case https://github.com/FaceDeer/settlements):
The text was updated successfully, but these errors were encountered: