diff --git a/chunky/src/java/se/llbit/chunky/world/Chunk.java b/chunky/src/java/se/llbit/chunky/world/Chunk.java index aae2e403f..092955ba8 100644 --- a/chunky/src/java/se/llbit/chunky/world/Chunk.java +++ b/chunky/src/java/se/llbit/chunky/world/Chunk.java @@ -17,6 +17,7 @@ package se.llbit.chunky.world; import se.llbit.chunky.block.minecraft.Air; +import it.unimi.dsi.fastutil.ints.IntIntImmutablePair; import se.llbit.chunky.block.Block; import se.llbit.chunky.block.minecraft.Lava; import se.llbit.chunky.block.minecraft.Water; @@ -179,7 +180,8 @@ public synchronized boolean loadChunk(@NotNull Mutable chunkData, int surfaceTimestamp = dataTimestamp; version = chunkVersion(data); - chunkData.set(this.dimension.createChunkData(chunkData.get(), data.get(DATAVERSION).intValue())); + IntIntImmutablePair chunkBounds = inclusiveChunkBounds(data); + chunkData.set(this.dimension.createChunkData(chunkData.get(), chunkBounds.leftInt(), chunkBounds.rightInt())); loadSurface(data, chunkData.get(), yMin, yMax); biomesTimestamp = dataTimestamp; @@ -461,8 +463,11 @@ public synchronized void getChunkData(@NotNull Mutable reuseChunkData Tag data = tagFromMap(dataMap); int dataVersion = data.get(DATAVERSION).intValue(); + + IntIntImmutablePair chunkBounds = inclusiveChunkBounds(data); + if(reuseChunkData.get() == null || reuseChunkData.get() instanceof EmptyChunkData) { - reuseChunkData.set(dimension.createChunkData(reuseChunkData.get(), dataVersion)); + reuseChunkData.set(dimension.createChunkData(reuseChunkData.get(), chunkBounds.leftInt(), chunkBounds.rightInt())); } else { reuseChunkData.get().clear(); } @@ -510,6 +515,28 @@ public synchronized void getChunkData(@NotNull Mutable reuseChunkData } } + /** + * @return The min and max blockY for a given section array + */ + private IntIntImmutablePair inclusiveChunkBounds(Tag chunkData) { + Tag sections = getTagFromNames(chunkData, LEVEL_SECTIONS, SECTIONS_POST_21W39A); + int minSectionY = Integer.MAX_VALUE; + int maxSectionY = Integer.MIN_VALUE; + if (sections.isList()) { + for (SpecificTag section : sections.asList()) { + byte sectionY = (byte) section.get("Y").byteValue(); + if (sectionY < minSectionY) { + minSectionY = sectionY; + } + if (sectionY > maxSectionY) { + maxSectionY = sectionY; + } + } + } + + return new IntIntImmutablePair(minSectionY << 4, (maxSectionY << 4) + 15); + } + /** * @return Integer index into a chunk YXZ array */ diff --git a/chunky/src/java/se/llbit/chunky/world/CubicDimension.java b/chunky/src/java/se/llbit/chunky/world/CubicDimension.java index f44e1a9bb..8f074c38c 100644 --- a/chunky/src/java/se/llbit/chunky/world/CubicDimension.java +++ b/chunky/src/java/se/llbit/chunky/world/CubicDimension.java @@ -36,7 +36,7 @@ public synchronized File getRegionDirectory() { } @Override - public ChunkData createChunkData(ChunkData chunkData, int chunkVersion) { + public ChunkData createChunkData(ChunkData chunkData, int minY, int maxY) { if (chunkData instanceof GenericChunkData) { return chunkData; } diff --git a/chunky/src/java/se/llbit/chunky/world/Dimension.java b/chunky/src/java/se/llbit/chunky/world/Dimension.java index e3d2aa3e9..187f86caa 100644 --- a/chunky/src/java/se/llbit/chunky/world/Dimension.java +++ b/chunky/src/java/se/llbit/chunky/world/Dimension.java @@ -100,18 +100,18 @@ public synchronized Chunk getChunk(ChunkPosition pos) { * Returns a ChunkData instance that is compatible with the given chunk version. * The provided ChunkData instance may or may not be re-used. */ - public ChunkData createChunkData(@Nullable ChunkData chunkData, int chunkVersion) { - if(chunkVersion >= World.VERSION_21W06A) { - if(chunkData instanceof GenericChunkData) { - return chunkData; - } - return new GenericChunkData(); - } else { - if(chunkData instanceof SimpleChunkData) { + public ChunkData createChunkData(@Nullable ChunkData chunkData, int minY, int maxY) { + if (minY >= 0 && maxY <= 255) { + if (chunkData instanceof SimpleChunkData) { return chunkData; } return new SimpleChunkData(); } + + if (chunkData instanceof GenericChunkData) { + return chunkData; + } + return new GenericChunkData(); } public Region createRegion(RegionPosition pos) { diff --git a/chunky/src/java/se/llbit/chunky/world/ImposterCubicChunk.java b/chunky/src/java/se/llbit/chunky/world/ImposterCubicChunk.java index 7ebac6410..1ea4ed846 100644 --- a/chunky/src/java/se/llbit/chunky/world/ImposterCubicChunk.java +++ b/chunky/src/java/se/llbit/chunky/world/ImposterCubicChunk.java @@ -67,7 +67,7 @@ public synchronized boolean loadChunk(@NotNull Mutable mutableChunkDa } surfaceTimestamp = dataTimestamp; - mutableChunkData.set(this.dimension.createChunkData(mutableChunkData.get(), 0)); //chunk version ignored for cubic worlds + mutableChunkData.set(this.dimension.createChunkData(mutableChunkData.get(), Integer.MIN_VALUE, Integer.MAX_VALUE)); ChunkData chunkData = mutableChunkData.get(); loadSurfaceCubic(data, chunkData, yMin, yMax); biomes = IconLayer.UNKNOWN; @@ -170,7 +170,7 @@ public synchronized void getChunkData(@NotNull Mutable reuseChunkData request.add(LEVEL_TILEENTITIES); Map> data = getCubeTags(request); if(reuseChunkData.get() == null || reuseChunkData.get() instanceof EmptyChunkData) { - reuseChunkData.set(dimension.createChunkData(reuseChunkData.get(), 0)); + reuseChunkData.set(dimension.createChunkData(reuseChunkData.get(), Integer.MIN_VALUE, Integer.MAX_VALUE)); } else { reuseChunkData.get().clear(); }