Add option to use ocean-floor-heightmap to improve cave-detection

This commit is contained in:
Lukas Rieger (Blue) 2022-10-23 00:52:39 +02:00
parent 9a989149fc
commit ff100e2656
No known key found for this signature in database
GPG Key ID: 2D09EC5ED2687FF2
12 changed files with 155 additions and 17 deletions

View File

@ -337,7 +337,7 @@ private ConfigTemplate createOverworldMapTemplate(String name, Path worldFolder)
.setVariable("sky-color", "#7dabff")
.setVariable("ambient-light", "0.1")
.setVariable("world-sky-light", "15")
.setVariable("remove-caves-below-y", "55")
.setVariable("remove-caves-below-y", "-2")
.setConditional("max-y-comment", true)
.setVariable("max-y", "100");
}

View File

@ -31,7 +31,7 @@ public class MapConfig implements MapSettings {
private int worldSkyLight = 15;
private int removeCavesBelowY = 55;
private int caveDetectionOceanFloor = 10000;
private boolean caveDetectionUsesBlockLight = false;
private int minX = Integer.MIN_VALUE;
@ -100,6 +100,10 @@ public boolean isCaveDetectionUsesBlockLight() {
return caveDetectionUsesBlockLight;
}
public int getCaveDetectionOceanFloor() {
return caveDetectionOceanFloor;
}
public Vector3i getMinPos() {
if (min == null) min = new Vector3i(minX, minY, minZ);
return min;

View File

@ -52,6 +52,13 @@ world-sky-light: ${world-sky-light}
# Default is 55 (slightly below water-level)
remove-caves-below-y: ${remove-caves-below-y}
# This is the amount of blocks relative to the "ocean-floor" heightmap that the cave-detection will start at.
# Everything above that (heightmap-relative) y-level will not be removed.
# Comment or set to a very high value to disable using the ocean-floor heightmap for cave-detection.
# Changing this value requires a re-render of the map.
# Defaults to 10000 (disabled)
cave-detection-ocean-floor: -5
# With this value set to true, BlueMap uses the block-light value instead of the sky-light value to "detect caves".
# (See: remove-caves-below-y)
# Changing this value requires a re-render of the map.

View File

@ -36,6 +36,11 @@ public interface RenderSettings {
*/
int getRemoveCavesBelowY();
/**
* The y-level relative to the ocean-floor heightmap below which caves will not be rendered
*/
int getCaveDetectionOceanFloor();
/**
* If blocklight should be used instead of sky light to detect "caves"
*/

View File

@ -71,6 +71,7 @@ public class LiquidModelBuilder {
private BlockModel modelResource;
private BlockModelView blockModel;
private Color blockColor;
private boolean isCave;
public LiquidModelBuilder(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) {
this.resourcePack = resourcePack;
@ -99,16 +100,17 @@ public void build(BlockNeighborhood<?> block, BlockState blockState, Variant var
this.blockModel = blockModel;
this.blockColor = color;
this.isCave =
this.block.getY() < renderSettings.getRemoveCavesBelowY() &&
this.block.getY() < block.getChunk().getOceanFloorY(block.getX(), block.getZ()) + renderSettings.getCaveDetectionOceanFloor();
build();
}
private final Color tintcolor = new Color();
private void build() {
// filter out blocks that are in a "cave" that should not be rendered
if (
this.block.getY() < renderSettings.getRemoveCavesBelowY() &&
(renderSettings.isCaveDetectionUsesBlockLight() ? block.getBlockLightLevel() : block.getSunLightLevel()) == 0f
) return;
if (this.isCave && (renderSettings.isCaveDetectionUsesBlockLight() ? block.getBlockLightLevel() : block.getSunLightLevel()) == 0f) return;
int level = blockState.getLiquidLevel();
if (level < 8 && !(level == 0 && isSameLiquid(block.getNeighborBlock(0, 1, 0)))){

View File

@ -73,6 +73,7 @@ public class ResourceModelBuilder {
private BlockModelView blockModel;
private Color blockColor;
private float blockColorOpacity;
private boolean isCave;
public ResourceModelBuilder(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) {
this.resourcePack = resourcePack;
@ -93,6 +94,10 @@ public void build(BlockNeighborhood<?> block, Variant variant, BlockModelView bl
this.variant = variant;
this.modelResource = variant.getModel().getResource();
this.isCave =
this.block.getY() < renderSettings.getRemoveCavesBelowY() &&
this.block.getY() < block.getChunk().getOceanFloorY(block.getX(), block.getZ()) + renderSettings.getCaveDetectionOceanFloor();
this.tintColor.set(0, 0, 0, -1, true);
// render model
@ -193,10 +198,7 @@ private void createElementFace(Element element, Direction faceDir, VectorM3f c0,
int blockLight = Math.max(blockLightData.getBlockLight(), facedLightData.getBlockLight());
// filter out faces that are in a "cave" that should not be rendered
if (
this.block.getY() < renderSettings.getRemoveCavesBelowY() &&
(renderSettings.isCaveDetectionUsesBlockLight() ? blockLight : sunLight) == 0f
) return;
if (isCave && (renderSettings.isCaveDetectionUsesBlockLight() ? blockLight : sunLight) == 0f) return;
// initialize the faces
blockModel.initialize();

View File

@ -35,13 +35,19 @@
import java.util.Map;
import java.util.Map.Entry;
@SuppressWarnings("FieldMayBeFinal")
public class ChunkAnvil113 extends MCAChunk {
private static final long[] EMPTY_LONG_ARRAY = new long[0];
private boolean isGenerated;
private boolean hasLight;
private long inhabitedTime;
private Section[] sections;
private int[] biomes;
private long[] oceanFloorHeights = EMPTY_LONG_ARRAY;
private long[] worldSurfaceHeights = EMPTY_LONG_ARRAY;
@SuppressWarnings("unchecked")
public ChunkAnvil113(MCAWorld world, CompoundTag chunkTag) {
super(world, chunkTag);
@ -58,6 +64,12 @@ public ChunkAnvil113(MCAWorld world, CompoundTag chunkTag) {
isGenerated = !status.equals("empty");
}
if (levelData.containsKey("Heightmaps")) {
CompoundTag heightmapsTag = levelData.getCompoundTag("Heightmaps");
this.worldSurfaceHeights = heightmapsTag.getLongArray("WORLD_SURFACE");
this.oceanFloorHeights = heightmapsTag.getLongArray("OCEAN_FLOOR");
}
sections = new Section[32]; //32 supports a max world-height of 512 which is the max that the hightmaps of Minecraft V1.13+ can store with 9 bits, i believe?
if (levelData.containsKey("Sections")) {
for (CompoundTag sectionTag : ((ListTag<CompoundTag>) levelData.getListTag("Sections"))) {
@ -127,8 +139,7 @@ public LightData getLightData(int x, int y, int z, LightData target) {
@Override
public String getBiome(int x, int y, int z) {
x = x & 0xF; // Math.floorMod(pos.getX(), 16)
z = z & 0xF;
x &= 0xF; z &= 0xF;
int biomeIntIndex = z * 16 + x;
if (biomeIntIndex >= this.biomes.length) return Biome.DEFAULT.getFormatted();
@ -136,7 +147,23 @@ public String getBiome(int x, int y, int z) {
return LegacyBiomes.idFor(biomes[biomeIntIndex]);
}
private class Section {
@Override
public int getWorldSurfaceY(int x, int z) {
if (this.worldSurfaceHeights.length < 36) return 0;
x &= 0xF; z &= 0xF;
return (int) MCAMath.getValueFromLongStream(this.worldSurfaceHeights, z * 16 + x, 9);
}
@Override
public int getOceanFloorY(int x, int z) {
if (this.oceanFloorHeights.length < 36) return 0;
x &= 0xF; z &= 0xF;
return (int) MCAMath.getValueFromLongStream(this.oceanFloorHeights, z * 16 + x, 9);
}
private static class Section {
private static final String AIR_ID = "minecraft:air";
private int sectionY;

View File

@ -35,13 +35,19 @@
import java.util.Map;
import java.util.Map.Entry;
@SuppressWarnings("FieldMayBeFinal")
public class ChunkAnvil115 extends MCAChunk {
private static final long[] EMPTY_LONG_ARRAY = new long[0];
private boolean isGenerated;
private boolean hasLight;
private long inhabitedTime;
private Section[] sections;
private int[] biomes;
private long[] oceanFloorHeights = EMPTY_LONG_ARRAY;
private long[] worldSurfaceHeights = EMPTY_LONG_ARRAY;
@SuppressWarnings("unchecked")
public ChunkAnvil115(MCAWorld world, CompoundTag chunkTag) {
super(world, chunkTag);
@ -58,6 +64,12 @@ public ChunkAnvil115(MCAWorld world, CompoundTag chunkTag) {
isGenerated = !status.equals("empty");
}
if (levelData.containsKey("Heightmaps")) {
CompoundTag heightmapsTag = levelData.getCompoundTag("Heightmaps");
this.worldSurfaceHeights = heightmapsTag.getLongArray("WORLD_SURFACE");
this.oceanFloorHeights = heightmapsTag.getLongArray("OCEAN_FLOOR");
}
sections = new Section[32]; //32 supports a max world-height of 512 which is the max that the hightmaps of Minecraft V1.13+ can store with 9 bits, i believe?
if (levelData.containsKey("Sections")) {
for (CompoundTag sectionTag : ((ListTag<CompoundTag>) levelData.getListTag("Sections"))) {
@ -138,6 +150,22 @@ public String getBiome(int x, int y, int z) {
return LegacyBiomes.idFor(biomes[biomeIntIndex]);
}
@Override
public int getWorldSurfaceY(int x, int z) {
if (this.worldSurfaceHeights.length < 36) return 0;
x &= 0xF; z &= 0xF;
return (int) MCAMath.getValueFromLongStream(this.worldSurfaceHeights, z * 16 + x, 9);
}
@Override
public int getOceanFloorY(int x, int z) {
if (this.oceanFloorHeights.length < 36) return 0;
x &= 0xF; z &= 0xF;
return (int) MCAMath.getValueFromLongStream(this.oceanFloorHeights, z * 16 + x, 9);
}
private static class Section {
private static final String AIR_ID = "minecraft:air";

View File

@ -36,7 +36,10 @@
import java.util.Map;
import java.util.Map.Entry;
@SuppressWarnings("FieldMayBeFinal")
public class ChunkAnvil116 extends MCAChunk {
private static final long[] EMPTY_LONG_ARRAY = new long[0];
private boolean isGenerated;
private boolean hasLight;
@ -47,6 +50,9 @@ public class ChunkAnvil116 extends MCAChunk {
private int[] biomes;
private long[] oceanFloorHeights = EMPTY_LONG_ARRAY;
private long[] worldSurfaceHeights = EMPTY_LONG_ARRAY;
@SuppressWarnings("unchecked")
public ChunkAnvil116(MCAWorld world, CompoundTag chunkTag) {
super(world, chunkTag);
@ -63,6 +69,12 @@ public ChunkAnvil116(MCAWorld world, CompoundTag chunkTag) {
isGenerated = !status.equals("empty");
}
if (levelData.containsKey("Heightmaps")) {
CompoundTag heightmapsTag = levelData.getCompoundTag("Heightmaps");
this.worldSurfaceHeights = heightmapsTag.getLongArray("WORLD_SURFACE");
this.oceanFloorHeights = heightmapsTag.getLongArray("OCEAN_FLOOR");
}
if (levelData.containsKey("Sections")) {
this.sectionMin = Integer.MAX_VALUE;
this.sectionMax = Integer.MIN_VALUE;
@ -166,6 +178,22 @@ public int getMaxY(int x, int z) {
return sectionMax * 16 + 15;
}
@Override
public int getWorldSurfaceY(int x, int z) {
if (this.worldSurfaceHeights.length < 37) return 0;
x &= 0xF; z &= 0xF;
return (int) MCAMath.getValueFromLongArray(this.worldSurfaceHeights, z * 16 + x, 9);
}
@Override
public int getOceanFloorY(int x, int z) {
if (this.oceanFloorHeights.length < 37) return 0;
x &= 0xF; z &= 0xF;
return (int) MCAMath.getValueFromLongArray(this.oceanFloorHeights, z * 16 + x, 9);
}
private Section getSection(int y) {
y -= sectionMin;
if (y < 0 || y >= this.sections.length) return null;

View File

@ -35,6 +35,10 @@
@SuppressWarnings("FieldMayBeFinal")
public class ChunkAnvil118 extends MCAChunk {
private static final long[] EMPTY_LONG_ARRAY = new long[0];
private static final BlockState[] EMPTY_BLOCK_STATE_ARRAY = new BlockState[0];
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private boolean isGenerated;
private boolean hasLight;
@ -43,6 +47,9 @@ public class ChunkAnvil118 extends MCAChunk {
private int sectionMin, sectionMax;
private Section[] sections;
private long[] oceanFloorHeights = EMPTY_LONG_ARRAY;
private long[] worldSurfaceHeights = EMPTY_LONG_ARRAY;
@SuppressWarnings("unchecked")
public ChunkAnvil118(MCAWorld world, CompoundTag chunkTag) {
super(world, chunkTag);
@ -57,6 +64,12 @@ public ChunkAnvil118(MCAWorld world, CompoundTag chunkTag) {
isGenerated = !status.equals("empty");
}
if (chunkTag.containsKey("Heightmaps")) {
CompoundTag heightmapsTag = chunkTag.getCompoundTag("Heightmaps");
this.worldSurfaceHeights = heightmapsTag.getLongArray("WORLD_SURFACE");
this.oceanFloorHeights = heightmapsTag.getLongArray("OCEAN_FLOOR");
}
if (chunkTag.containsKey("sections")) {
this.sectionMin = Integer.MAX_VALUE;
this.sectionMax = Integer.MIN_VALUE;
@ -136,6 +149,22 @@ public int getMaxY(int x, int z) {
return sectionMax * 16 + 15;
}
@Override
public int getWorldSurfaceY(int x, int z) {
if (this.worldSurfaceHeights.length < 37) return 0;
x &= 0xF; z &= 0xF;
return (int) MCAMath.getValueFromLongArray(this.worldSurfaceHeights, z * 16 + x, 9) - 64;
}
@Override
public int getOceanFloorY(int x, int z) {
if (this.oceanFloorHeights.length < 37) return 0;
x &= 0xF; z &= 0xF;
return (int) MCAMath.getValueFromLongArray(this.oceanFloorHeights, z * 16 + x, 9) - 64;
}
private Section getSection(int y) {
y -= sectionMin;
if (y < 0 || y >= this.sections.length) return null;
@ -143,10 +172,6 @@ private Section getSection(int y) {
}
private static class Section {
private static final long[] EMPTY_LONG_ARRAY = new long[0];
private static final BlockState[] EMPTY_BLOCK_STATE_ARRAY = new BlockState[0];
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private int sectionY;
private byte[] blockLight;
private byte[] skyLight;

View File

@ -81,6 +81,12 @@ public int getMinY(int x, int z) {
return 0;
}
@Override
public int getWorldSurfaceY(int x, int z) { return 0; }
@Override
public int getOceanFloorY(int x, int z) { return 0; }
protected MCAWorld getWorld() {
return world;
}

View File

@ -42,4 +42,8 @@ public interface Chunk {
int getMinY(int x, int z);
int getWorldSurfaceY(int x, int z);
int getOceanFloorY(int x, int z);
}