-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Fix mgValleys getSpawnLevelAtPoint() #7756
Conversation
adjustedTerrainLevelFromNoise() only adds the effect of inter_valley_fill 3D noise when the noise is raising the terrain height, but sometimes the noise lowers the terrain height, and this can lower it below sea-level.
Thanks. Mgvalleys does have an occasional spawn bug, which suggests you may be right. Good mapgen, but mgvalleys was added far too easily and the code was too messy when it was added, we've learned out lesson now and will be much more strict on new mapgens. |
Sorry about that, but I never intended to suggest that I understood how the algorithms worked. Gael de Sailly's theory is over my head. I just hoped to port it from lua to C++. I tend to suspect that the terrain generation is in the right here. A lot of changes have been made to the spawn location code from the original lua, which used a very different method. But I wouldn't worry too much about it, since it's diverged quite a bit all around. |
Duane, no problem, the mistake was ours and mostly mine for approving it without fully understanding the code first. I made the mistake of assuming you understood it fully and would maintain it. |
I haven't learned the thinking behind the noise either, but I spent a lot of time staring at We can treat For every y value, OTOH The changed code scans up looking for air if the node at preliminary_ground_height is ground, and scans down looking for ground if if the node at preliminary_ground_height is air. Reading through this old issue from 2016 suggests the behaviour may have been known, but in my mind fixing it should make it more easily able to find a spawn because adjustedTerrainLevelFromNoise() will often return lower values than it currently does, and the problem was finding locations lower than 16. There's some talk of rivers which I'm not clear about but those locations are eliminated by code in getSpawnLevelAtPoint(). |
src/mapgen/mapgen_valleys.cpp
Outdated
bool was_ground = is_ground; | ||
is_ground = fill * *tn->slope >= y - mount; | ||
if (is_ground) result = y; | ||
if (is_ground != was_ground) break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For both these conditionals the action should be indented on the following line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this will work for when the initial ground level is air, as result
won't be reduced as this searches downwards. So when result
is returned it will still be the initial level.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the initial ground level is air, the result will be reduced upon finding the first ground block.
I'll clean these other things up.
Having a separate search loop for each direction and an if statement to select which one to use might have been a more easily readable way of writing it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes just realised this will work. Is fine then.
src/mapgen/mapgen_valleys.cpp
Outdated
@@ -393,18 +393,26 @@ float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn) | |||
float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn) | |||
{ | |||
float mount = terrainLevelFromNoise(tn); | |||
float result = mount; | |||
s16 y_start = myround(mount); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for this empty line.
} | ||
|
||
return mount; | ||
return result; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
result + 1
to account for biome dust that can be 1 node deep, other mapgens also + 1
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've put the +1 in getSpawnLevelAtPoint() - it seemed appropriate there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fine.
I can see you are correct about the cause of the bug. The code of this mapgen is so overcomplex and confusing i might have to rewrite it after 5.0.0 so people have a chance to understand it :] |
Code looks fine, will test. |
👍 tests fine. |
adjustedTerrainLevelFromNoise() will only add the effect of inter_valley_fill 3D noise when the noise is raising the terrain height, but sometimes the noise lowers the terrain height, and this can lower it below sea-level.
For example, on seed 1, calling
minetest.get_spawn_level(-1400, 520)
in Lua returns 4, but this location is ocean:The code in this pull request is a C++ port of the fix made in Amidst, which had the results shown below, but I have not tested or even compiled this C++ code as I don't have a Minetest build environment set up (yay for Travis CI!).
(note I've assumed the terrain generation is authoritative, if the mgValleys author only intended 3D noise to raise the terrain height, then adjustedTerrainLevelFromNoise() might be correct and the terrain generation might be wrong)