The bugs listed here all stem from the bugged method in the screenshot(Level.getSeaLevel). Several bug reports were NOT made because fixing this singular bugged method would fix all the bugs listed.
Since 1.16's datapack system has been introduced, sea level has become a configurable argument in the chunk generator.
But there's one issue, a lot of places still assume that sea level is 63 when this is no longer the case when changing the sea level in the chunk generator.
I've attached the TallOceansTest & SnowTestUnder63 Datapack to recreate these issues listed.
This source of the issue can be narrowed down to `Level.getSeaLevel` method and usages of it as shown here:
This means all usages of this method, are possibly "broken" when this value is not changed together with Chunk Generator's sea level.
My solution:
In ServerLevel, override this method and call: this.chunkSource.getGenerator.getSeaLevel and on the client you'd most likely need some sort of packet containing the sea level of the current chunk generator/ServerLevel.
Here are a list of issues that may occur when changing sea level:
1. Dolphins, Drowned, Turtles, & Squid spawning does not occur in oceans in water when sea level is above Y 63.
No real good way to visualize this. But I've attached a datapack which increases both ocean depth & and the chunk generator's sea level to show this issue. All of the code for these can be found in the respective Mob's spawn rules.
2. Axolotls & Glowsquid spawning only occurs when the Ocean Floor Heightmap is under Y 63 as seen here in the `WaterAnimal` class:
public static boolean checkUndergroundWaterCreatureSpawnRules(EntityType<? extends LivingEntity> entityType, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, Random random) { return pos.getY() < world.getSeaLevel() && pos.getY() < world.getHeight(Heightmap.Types.OCEAN_FLOOR, pos.getX(), pos.getZ()); }
3. Ocelot spawning is not obstructed under the chunk generator sea level(when above 63) and ALWAYS obstructed when Chunk Generator sea level/terrain is under 63.
As seen here in the `Ocelot` class.
public boolean checkSpawnObstruction(LevelReader world) { if (world.isUnobstructed(this) && !world.containsAnyLiquid(this.getBoundingBox())) { BlockPos blockPos = this.blockPosition(); if (blockPos.getY() < world.getSeaLevel()) { return false; } BlockState blockState = world.getBlockState(blockPos.below()); if (blockState.is(Blocks.GRASS_BLOCK) || blockState.is(BlockTags.LEAVES)) { return true; } } return false; }
4. Phantom Anchor Point is set to Y 64 when under Y 63 when Chunk Generator Sea Level is different
This may or may not be correct but the intention seems to be that the anchor point when under sea level(what I would believe should be the Chunk Generator's sea level) should be +1 on the Chunk Generator Sea Level. As seen here in the `Phantom.setAnchorAboveTarget` class:
private void setAnchorAboveTarget() { Phantom.this.anchorPoint = Phantom.this.getTarget().blockPosition().above(20 + Phantom.this.random.nextInt(20)); if (Phantom.this.anchorPoint.getY() < Phantom.this.level.getSeaLevel()) { Phantom.this.anchorPoint = new BlockPos(Phantom.this.anchorPoint.getX(), Phantom.this.level.getSeaLevel() + 1, Phantom.this.anchorPoint.getZ()); } } }
5. Bats do not spawn in caves under the Chunk Generator's elevated sea level and are guaranteed to spawn where the Chunk Generator's sea level is lower than 63. As seen here in Bat.checkBatSpawnRules:
public static boolean checkBatSpawnRules(EntityType<Bat> type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, Random random) { if (pos.getY() >= world.getSeaLevel()) { return false; } else { int i = world.getMaxLocalRawBrightness(pos); int j = 4; if (isHalloween()) { j = 7; } else if (random.nextBoolean()) { return false; } return i > random.nextInt(j) ? false : checkMobSpawnRules(type, world, spawnReason, pos, random); } }
6. Drowned cannot spawn above Y 58 and are always deep enough to spawn in any fluids under Y 58.
As seen here in Drowned.isDeepEnoughToSpawn:
private static boolean isDeepEnoughToSpawn(LevelAccessor world, BlockPos pos) { return pos.getY() < world.getSeaLevel() - 5; }
7. Blue Ice Feature will fail in water bodies above Y 62.
As seen in BlueIceFeature.place:
if (blockPos.getY() > worldGenLevel.getSeaLevel() - 1) { return false; }
8. Ocean monuments spawn at a hardcoded height of Y 63, disregarding ocean floor height/sea level. You can see that here: https://youtu.be/5lfsKyAyifI
The code that produces this can be found in 2 places in the `OceanMonumentPieces` class.
8a. OceanMonumentPieces.postProcess:
public boolean postProcess(WorldGenLevel world, StructureFeatureManager structureAccessor, ChunkGenerator chunkGenerator, Random random, BoundingBox boundingBox, ChunkPos chunkPos, BlockPos pos) { int i = Math.max(world.getSeaLevel(), 64) - this.boundingBox.minY();
8b. OceanMonumentPieces.generateWaterBox:
protected void generateWaterBox(WorldGenLevel world, BoundingBox box, int x, int y, int z, int width, int height, int depth) { for(int i = y; i <= height; ++i) { for(int j = x; j <= width; ++j) { for(int k = z; k <= depth; ++k) { BlockState blockState = this.getBlock(world, j, i, k, box); if (!FILL_KEEP.contains(blockState.getBlock())) { if (this.getWorldY(i) >= world.getSeaLevel() && blockState != FILL_BLOCK) { this.placeBlock(world, Blocks.AIR.defaultBlockState(), j, i, k, box); } else { this.placeBlock(world, FILL_BLOCK, j, i, k, box); } } } } } }
9. Blocks of air are ALWAYS placed in Ocean ruins when the chunk generator's sea level is ABOVE 63 or blocks of water are ALWAYS placed when Chunk Generator sea level is UNDER 63 in `handleDataMarker`.
As seen in OceanRuinPieces.handleDataMarker:
else if ("drowned".equals(metadata)) { Drowned drowned = (Drowned)EntityType.DROWNED.create(world.getLevel()); drowned.setPersistenceRequired(); drowned.moveTo(pos, 0.0F, 0.0F); drowned.finalizeSpawn(world, world.getCurrentDifficultyAt(pos), MobSpawnType.STRUCTURE, (SpawnGroupData)null, (CompoundTag)null); world.addFreshEntityWithPassengers(drowned); if (pos.getY() > world.getSeaLevel()) { world.setBlock(pos, Blocks.AIR.defaultBlockState(), 2); } else { world.setBlock(pos, Blocks.WATER.defaultBlockState(), 2); }
10. Axolotl & Turtle Path finding may produce inaccuracies in oceans w/ water above 53.
Not sure on enttiy AI myself but this issue can be seen in `AmphibiousNodeEvaluator.getNeighbors` when incrementing a Path Finding Node's cost malus:
public int getNeighbors(Node[] successors, Node node) { int i = super.getNeighbors(successors, node); BlockPathTypes blockPathTypes = this.getCachedBlockType(this.mob, node.x, node.y + 1, node.z); BlockPathTypes blockPathTypes2 = this.getCachedBlockType(this.mob, node.x, node.y, node.z); int k; if (this.mob.getPathfindingMalus(blockPathTypes) >= 0.0F && blockPathTypes2 != BlockPathTypes.STICKY_HONEY) { k = Mth.floor(Math.max(1.0F, this.mob.maxUpStep)); } else { k = 0; } double d = this.getFloorLevel(new BlockPos(node.x, node.y, node.z)); Node node2 = this.findAcceptedNode(node.x, node.y + 1, node.z, Math.max(0, k - 1), d, Direction.UP, blockPathTypes2); Node node3 = this.findAcceptedNode(node.x, node.y - 1, node.z, k, d, Direction.DOWN, blockPathTypes2); if (this.isNeighborValid(node2, node)) { successors[i++] = node2; } if (this.isNeighborValid(node3, node) && blockPathTypes2 != BlockPathTypes.TRAPDOOR) { successors[i++] = node3; } for(int l = 0; l < i; ++l) { Node node4 = successors[l]; if (node4.type == BlockPathTypes.WATER && this.prefersShallowSwimming && node4.y < this.mob.level.getSeaLevel() - 10) { ++node4.costMalus; } } return i; }
11. Phantom Spawning changes when sea level is changed from Y 63.
Issue can be found in: PantomSpawner.tick
12. Biome temperature height adjustment is hardcoded to Y 64(I presume this to be sea level + 1). You can see this issue very clearly here with these 2 images:
Vanilla:
Snow Test Under 63(Sea level is -12) datapack:
The code in question can be found in Biome.getHeightAdjustedTemperature:
private float getHeightAdjustedTemperature(BlockPos pos) { float f = this.climateSettings.temperatureModifier.modifyTemperature(pos, this.getBaseTemperature()); if (pos.getY() > 64) { float g = (float)(TEMPERATURE_NOISE.getValue((double)((float)pos.getX() / 8.0F), (double)((float)pos.getZ() / 8.0F), false) * 4.0D); return f - (g + (float)pos.getY() - 64.0F) * 0.05F / 30.0F; } else { return f; } }
- is duplicated by
-
MC-259341 Monument height unable to be modified
- Resolved
- relates to
-
MC-128659 Structures generate in the air in "Floating Islands" world generation
- Open
-
MC-210972 Drowned's pathfind AI will be buggy when Y>63
- Open
-
MC-249005 Strongholds can generate floating in superflat worlds
- Open
-
MC-87522 Villages can generate on void
- Reopened
-
MC-118103 Sky color depends on absolute height in world and changes abruptly
- Reopened
-
MC-278019 Superflat worlds have their sea level at Y=-63
- Open