Skip to content

Commit ff100e2

Browse files
committed
Add option to use ocean-floor-heightmap to improve cave-detection
1 parent 9a98914 commit ff100e2

File tree

12 files changed

+155
-17
lines changed

12 files changed

+155
-17
lines changed

BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigs.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ private ConfigTemplate createOverworldMapTemplate(String name, Path worldFolder)
337337
.setVariable("sky-color", "#7dabff")
338338
.setVariable("ambient-light", "0.1")
339339
.setVariable("world-sky-light", "15")
340-
.setVariable("remove-caves-below-y", "55")
340+
.setVariable("remove-caves-below-y", "-2")
341341
.setConditional("max-y-comment", true)
342342
.setVariable("max-y", "100");
343343
}

BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/MapConfig.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public class MapConfig implements MapSettings {
3131
private int worldSkyLight = 15;
3232

3333
private int removeCavesBelowY = 55;
34-
34+
private int caveDetectionOceanFloor = 10000;
3535
private boolean caveDetectionUsesBlockLight = false;
3636

3737
private int minX = Integer.MIN_VALUE;
@@ -100,6 +100,10 @@ public boolean isCaveDetectionUsesBlockLight() {
100100
return caveDetectionUsesBlockLight;
101101
}
102102

103+
public int getCaveDetectionOceanFloor() {
104+
return caveDetectionOceanFloor;
105+
}
106+
103107
public Vector3i getMinPos() {
104108
if (min == null) min = new Vector3i(minX, minY, minZ);
105109
return min;

BlueMapCommon/src/main/resources/de/bluecolored/bluemap/config/maps/map.conf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ world-sky-light: ${world-sky-light}
5252
# Default is 55 (slightly below water-level)
5353
remove-caves-below-y: ${remove-caves-below-y}
5454

55+
# This is the amount of blocks relative to the "ocean-floor" heightmap that the cave-detection will start at.
56+
# Everything above that (heightmap-relative) y-level will not be removed.
57+
# Comment or set to a very high value to disable using the ocean-floor heightmap for cave-detection.
58+
# Changing this value requires a re-render of the map.
59+
# Defaults to 10000 (disabled)
60+
cave-detection-ocean-floor: -5
61+
5562
# With this value set to true, BlueMap uses the block-light value instead of the sky-light value to "detect caves".
5663
# (See: remove-caves-below-y)
5764
# Changing this value requires a re-render of the map.

BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/RenderSettings.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ public interface RenderSettings {
3636
*/
3737
int getRemoveCavesBelowY();
3838

39+
/**
40+
* The y-level relative to the ocean-floor heightmap below which caves will not be rendered
41+
*/
42+
int getCaveDetectionOceanFloor();
43+
3944
/**
4045
* If blocklight should be used instead of sky light to detect "caves"
4146
*/

BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/blockmodel/LiquidModelBuilder.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public class LiquidModelBuilder {
7171
private BlockModel modelResource;
7272
private BlockModelView blockModel;
7373
private Color blockColor;
74+
private boolean isCave;
7475

7576
public LiquidModelBuilder(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) {
7677
this.resourcePack = resourcePack;
@@ -99,16 +100,17 @@ public void build(BlockNeighborhood<?> block, BlockState blockState, Variant var
99100
this.blockModel = blockModel;
100101
this.blockColor = color;
101102

103+
this.isCave =
104+
this.block.getY() < renderSettings.getRemoveCavesBelowY() &&
105+
this.block.getY() < block.getChunk().getOceanFloorY(block.getX(), block.getZ()) + renderSettings.getCaveDetectionOceanFloor();
106+
102107
build();
103108
}
104109

105110
private final Color tintcolor = new Color();
106111
private void build() {
107112
// filter out blocks that are in a "cave" that should not be rendered
108-
if (
109-
this.block.getY() < renderSettings.getRemoveCavesBelowY() &&
110-
(renderSettings.isCaveDetectionUsesBlockLight() ? block.getBlockLightLevel() : block.getSunLightLevel()) == 0f
111-
) return;
113+
if (this.isCave && (renderSettings.isCaveDetectionUsesBlockLight() ? block.getBlockLightLevel() : block.getSunLightLevel()) == 0f) return;
112114

113115
int level = blockState.getLiquidLevel();
114116
if (level < 8 && !(level == 0 && isSameLiquid(block.getNeighborBlock(0, 1, 0)))){

BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/blockmodel/ResourceModelBuilder.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public class ResourceModelBuilder {
7373
private BlockModelView blockModel;
7474
private Color blockColor;
7575
private float blockColorOpacity;
76+
private boolean isCave;
7677

7778
public ResourceModelBuilder(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) {
7879
this.resourcePack = resourcePack;
@@ -93,6 +94,10 @@ public void build(BlockNeighborhood<?> block, Variant variant, BlockModelView bl
9394
this.variant = variant;
9495
this.modelResource = variant.getModel().getResource();
9596

97+
this.isCave =
98+
this.block.getY() < renderSettings.getRemoveCavesBelowY() &&
99+
this.block.getY() < block.getChunk().getOceanFloorY(block.getX(), block.getZ()) + renderSettings.getCaveDetectionOceanFloor();
100+
96101
this.tintColor.set(0, 0, 0, -1, true);
97102

98103
// render model
@@ -193,10 +198,7 @@ private void createElementFace(Element element, Direction faceDir, VectorM3f c0,
193198
int blockLight = Math.max(blockLightData.getBlockLight(), facedLightData.getBlockLight());
194199

195200
// filter out faces that are in a "cave" that should not be rendered
196-
if (
197-
this.block.getY() < renderSettings.getRemoveCavesBelowY() &&
198-
(renderSettings.isCaveDetectionUsesBlockLight() ? blockLight : sunLight) == 0f
199-
) return;
201+
if (isCave && (renderSettings.isCaveDetectionUsesBlockLight() ? blockLight : sunLight) == 0f) return;
200202

201203
// initialize the faces
202204
blockModel.initialize();

BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil113.java

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,19 @@
3535
import java.util.Map;
3636
import java.util.Map.Entry;
3737

38+
@SuppressWarnings("FieldMayBeFinal")
3839
public class ChunkAnvil113 extends MCAChunk {
40+
private static final long[] EMPTY_LONG_ARRAY = new long[0];
41+
3942
private boolean isGenerated;
4043
private boolean hasLight;
4144
private long inhabitedTime;
4245
private Section[] sections;
4346
private int[] biomes;
4447

48+
private long[] oceanFloorHeights = EMPTY_LONG_ARRAY;
49+
private long[] worldSurfaceHeights = EMPTY_LONG_ARRAY;
50+
4551
@SuppressWarnings("unchecked")
4652
public ChunkAnvil113(MCAWorld world, CompoundTag chunkTag) {
4753
super(world, chunkTag);
@@ -58,6 +64,12 @@ public ChunkAnvil113(MCAWorld world, CompoundTag chunkTag) {
5864
isGenerated = !status.equals("empty");
5965
}
6066

67+
if (levelData.containsKey("Heightmaps")) {
68+
CompoundTag heightmapsTag = levelData.getCompoundTag("Heightmaps");
69+
this.worldSurfaceHeights = heightmapsTag.getLongArray("WORLD_SURFACE");
70+
this.oceanFloorHeights = heightmapsTag.getLongArray("OCEAN_FLOOR");
71+
}
72+
6173
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?
6274
if (levelData.containsKey("Sections")) {
6375
for (CompoundTag sectionTag : ((ListTag<CompoundTag>) levelData.getListTag("Sections"))) {
@@ -127,16 +139,31 @@ public LightData getLightData(int x, int y, int z, LightData target) {
127139

128140
@Override
129141
public String getBiome(int x, int y, int z) {
130-
x = x & 0xF; // Math.floorMod(pos.getX(), 16)
131-
z = z & 0xF;
142+
x &= 0xF; z &= 0xF;
132143
int biomeIntIndex = z * 16 + x;
133144

134145
if (biomeIntIndex >= this.biomes.length) return Biome.DEFAULT.getFormatted();
135146

136147
return LegacyBiomes.idFor(biomes[biomeIntIndex]);
137148
}
138149

139-
private class Section {
150+
@Override
151+
public int getWorldSurfaceY(int x, int z) {
152+
if (this.worldSurfaceHeights.length < 36) return 0;
153+
154+
x &= 0xF; z &= 0xF;
155+
return (int) MCAMath.getValueFromLongStream(this.worldSurfaceHeights, z * 16 + x, 9);
156+
}
157+
158+
@Override
159+
public int getOceanFloorY(int x, int z) {
160+
if (this.oceanFloorHeights.length < 36) return 0;
161+
162+
x &= 0xF; z &= 0xF;
163+
return (int) MCAMath.getValueFromLongStream(this.oceanFloorHeights, z * 16 + x, 9);
164+
}
165+
166+
private static class Section {
140167
private static final String AIR_ID = "minecraft:air";
141168

142169
private int sectionY;

BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil115.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,19 @@
3535
import java.util.Map;
3636
import java.util.Map.Entry;
3737

38+
@SuppressWarnings("FieldMayBeFinal")
3839
public class ChunkAnvil115 extends MCAChunk {
40+
private static final long[] EMPTY_LONG_ARRAY = new long[0];
41+
3942
private boolean isGenerated;
4043
private boolean hasLight;
4144
private long inhabitedTime;
4245
private Section[] sections;
4346
private int[] biomes;
4447

48+
private long[] oceanFloorHeights = EMPTY_LONG_ARRAY;
49+
private long[] worldSurfaceHeights = EMPTY_LONG_ARRAY;
50+
4551
@SuppressWarnings("unchecked")
4652
public ChunkAnvil115(MCAWorld world, CompoundTag chunkTag) {
4753
super(world, chunkTag);
@@ -58,6 +64,12 @@ public ChunkAnvil115(MCAWorld world, CompoundTag chunkTag) {
5864
isGenerated = !status.equals("empty");
5965
}
6066

67+
if (levelData.containsKey("Heightmaps")) {
68+
CompoundTag heightmapsTag = levelData.getCompoundTag("Heightmaps");
69+
this.worldSurfaceHeights = heightmapsTag.getLongArray("WORLD_SURFACE");
70+
this.oceanFloorHeights = heightmapsTag.getLongArray("OCEAN_FLOOR");
71+
}
72+
6173
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?
6274
if (levelData.containsKey("Sections")) {
6375
for (CompoundTag sectionTag : ((ListTag<CompoundTag>) levelData.getListTag("Sections"))) {
@@ -138,6 +150,22 @@ public String getBiome(int x, int y, int z) {
138150
return LegacyBiomes.idFor(biomes[biomeIntIndex]);
139151
}
140152

153+
@Override
154+
public int getWorldSurfaceY(int x, int z) {
155+
if (this.worldSurfaceHeights.length < 36) return 0;
156+
157+
x &= 0xF; z &= 0xF;
158+
return (int) MCAMath.getValueFromLongStream(this.worldSurfaceHeights, z * 16 + x, 9);
159+
}
160+
161+
@Override
162+
public int getOceanFloorY(int x, int z) {
163+
if (this.oceanFloorHeights.length < 36) return 0;
164+
165+
x &= 0xF; z &= 0xF;
166+
return (int) MCAMath.getValueFromLongStream(this.oceanFloorHeights, z * 16 + x, 9);
167+
}
168+
141169
private static class Section {
142170
private static final String AIR_ID = "minecraft:air";
143171

BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil116.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@
3636
import java.util.Map;
3737
import java.util.Map.Entry;
3838

39+
@SuppressWarnings("FieldMayBeFinal")
3940
public class ChunkAnvil116 extends MCAChunk {
41+
private static final long[] EMPTY_LONG_ARRAY = new long[0];
42+
4043
private boolean isGenerated;
4144
private boolean hasLight;
4245

@@ -47,6 +50,9 @@ public class ChunkAnvil116 extends MCAChunk {
4750

4851
private int[] biomes;
4952

53+
private long[] oceanFloorHeights = EMPTY_LONG_ARRAY;
54+
private long[] worldSurfaceHeights = EMPTY_LONG_ARRAY;
55+
5056
@SuppressWarnings("unchecked")
5157
public ChunkAnvil116(MCAWorld world, CompoundTag chunkTag) {
5258
super(world, chunkTag);
@@ -63,6 +69,12 @@ public ChunkAnvil116(MCAWorld world, CompoundTag chunkTag) {
6369
isGenerated = !status.equals("empty");
6470
}
6571

72+
if (levelData.containsKey("Heightmaps")) {
73+
CompoundTag heightmapsTag = levelData.getCompoundTag("Heightmaps");
74+
this.worldSurfaceHeights = heightmapsTag.getLongArray("WORLD_SURFACE");
75+
this.oceanFloorHeights = heightmapsTag.getLongArray("OCEAN_FLOOR");
76+
}
77+
6678
if (levelData.containsKey("Sections")) {
6779
this.sectionMin = Integer.MAX_VALUE;
6880
this.sectionMax = Integer.MIN_VALUE;
@@ -166,6 +178,22 @@ public int getMaxY(int x, int z) {
166178
return sectionMax * 16 + 15;
167179
}
168180

181+
@Override
182+
public int getWorldSurfaceY(int x, int z) {
183+
if (this.worldSurfaceHeights.length < 37) return 0;
184+
185+
x &= 0xF; z &= 0xF;
186+
return (int) MCAMath.getValueFromLongArray(this.worldSurfaceHeights, z * 16 + x, 9);
187+
}
188+
189+
@Override
190+
public int getOceanFloorY(int x, int z) {
191+
if (this.oceanFloorHeights.length < 37) return 0;
192+
193+
x &= 0xF; z &= 0xF;
194+
return (int) MCAMath.getValueFromLongArray(this.oceanFloorHeights, z * 16 + x, 9);
195+
}
196+
169197
private Section getSection(int y) {
170198
y -= sectionMin;
171199
if (y < 0 || y >= this.sections.length) return null;

BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil118.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535

3636
@SuppressWarnings("FieldMayBeFinal")
3737
public class ChunkAnvil118 extends MCAChunk {
38+
private static final long[] EMPTY_LONG_ARRAY = new long[0];
39+
private static final BlockState[] EMPTY_BLOCK_STATE_ARRAY = new BlockState[0];
40+
private static final String[] EMPTY_STRING_ARRAY = new String[0];
41+
3842
private boolean isGenerated;
3943
private boolean hasLight;
4044

@@ -43,6 +47,9 @@ public class ChunkAnvil118 extends MCAChunk {
4347
private int sectionMin, sectionMax;
4448
private Section[] sections;
4549

50+
private long[] oceanFloorHeights = EMPTY_LONG_ARRAY;
51+
private long[] worldSurfaceHeights = EMPTY_LONG_ARRAY;
52+
4653
@SuppressWarnings("unchecked")
4754
public ChunkAnvil118(MCAWorld world, CompoundTag chunkTag) {
4855
super(world, chunkTag);
@@ -57,6 +64,12 @@ public ChunkAnvil118(MCAWorld world, CompoundTag chunkTag) {
5764
isGenerated = !status.equals("empty");
5865
}
5966

67+
if (chunkTag.containsKey("Heightmaps")) {
68+
CompoundTag heightmapsTag = chunkTag.getCompoundTag("Heightmaps");
69+
this.worldSurfaceHeights = heightmapsTag.getLongArray("WORLD_SURFACE");
70+
this.oceanFloorHeights = heightmapsTag.getLongArray("OCEAN_FLOOR");
71+
}
72+
6073
if (chunkTag.containsKey("sections")) {
6174
this.sectionMin = Integer.MAX_VALUE;
6275
this.sectionMax = Integer.MIN_VALUE;
@@ -136,17 +149,29 @@ public int getMaxY(int x, int z) {
136149
return sectionMax * 16 + 15;
137150
}
138151

152+
@Override
153+
public int getWorldSurfaceY(int x, int z) {
154+
if (this.worldSurfaceHeights.length < 37) return 0;
155+
156+
x &= 0xF; z &= 0xF;
157+
return (int) MCAMath.getValueFromLongArray(this.worldSurfaceHeights, z * 16 + x, 9) - 64;
158+
}
159+
160+
@Override
161+
public int getOceanFloorY(int x, int z) {
162+
if (this.oceanFloorHeights.length < 37) return 0;
163+
164+
x &= 0xF; z &= 0xF;
165+
return (int) MCAMath.getValueFromLongArray(this.oceanFloorHeights, z * 16 + x, 9) - 64;
166+
}
167+
139168
private Section getSection(int y) {
140169
y -= sectionMin;
141170
if (y < 0 || y >= this.sections.length) return null;
142171
return this.sections[y];
143172
}
144173

145174
private static class Section {
146-
private static final long[] EMPTY_LONG_ARRAY = new long[0];
147-
private static final BlockState[] EMPTY_BLOCK_STATE_ARRAY = new BlockState[0];
148-
private static final String[] EMPTY_STRING_ARRAY = new String[0];
149-
150175
private int sectionY;
151176
private byte[] blockLight;
152177
private byte[] skyLight;

0 commit comments

Comments
 (0)