Skip to content

Commit

Permalink
ChunkData creation now checks against chunk bounds, rather than chunk…
Browse files Browse the repository at this point in the history
… version.

This fixes annoying ChunkDataVersion issues with third-party apps like WorldPainter
  • Loading branch information
NotStirred committed Sep 23, 2024
1 parent 16b409c commit 69d167d
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 13 deletions.
31 changes: 29 additions & 2 deletions chunky/src/java/se/llbit/chunky/world/Chunk.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -179,7 +180,8 @@ public synchronized boolean loadChunk(@NotNull Mutable<ChunkData> 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;

Expand Down Expand Up @@ -461,8 +463,11 @@ public synchronized void getChunkData(@NotNull Mutable<ChunkData> 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();
}
Expand Down Expand Up @@ -510,6 +515,28 @@ public synchronized void getChunkData(@NotNull Mutable<ChunkData> 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
*/
Expand Down
2 changes: 1 addition & 1 deletion chunky/src/java/se/llbit/chunky/world/CubicDimension.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
16 changes: 8 additions & 8 deletions chunky/src/java/se/llbit/chunky/world/Dimension.java
Original file line number Diff line number Diff line change
Expand Up @@ -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(ChunkPosition pos) {
Expand Down
4 changes: 2 additions & 2 deletions chunky/src/java/se/llbit/chunky/world/ImposterCubicChunk.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public synchronized boolean loadChunk(@NotNull Mutable<ChunkData> 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;
Expand Down Expand Up @@ -170,7 +170,7 @@ public synchronized void getChunkData(@NotNull Mutable<ChunkData> reuseChunkData
request.add(LEVEL_TILEENTITIES);
Map<Integer, Map<String, Tag>> 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();
}
Expand Down

0 comments on commit 69d167d

Please sign in to comment.