Skip to content

Commit 75fd21a

Browse files
Properly calculate global BPE and add initial value for data palettes (#910)
* Reintroduce custom global palette BPE for DataPalettes, but this time smarter * Add initial state parameter to DataPalette * Rename chunk -> block state for clarity
1 parent 96f7061 commit 75fd21a

File tree

5 files changed

+46
-84
lines changed

5 files changed

+46
-84
lines changed

protocol/src/main/java/org/geysermc/mcprotocollib/protocol/codec/MinecraftTypes.java

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,7 +1332,7 @@ public static void writeSlotDisplay(ByteBuf buf, SlotDisplay display) {
13321332
}
13331333
}
13341334

1335-
public static DataPalette readDataPalette(ByteBuf buf, PaletteType paletteType) {
1335+
public static DataPalette readDataPalette(ByteBuf buf, PaletteType paletteType, int registrySize) {
13361336
int bitsPerEntry = buf.readByte() & 0xFF;
13371337
Palette palette = MinecraftTypes.readPalette(buf, paletteType, bitsPerEntry);
13381338
BitStorage storage;
@@ -1343,15 +1343,7 @@ public static DataPalette readDataPalette(ByteBuf buf, PaletteType paletteType)
13431343
MinecraftTypes.readFixedSizeLongArray(buf, storage.getData());
13441344
}
13451345

1346-
return new DataPalette(palette, storage, paletteType);
1347-
}
1348-
1349-
/**
1350-
* @deprecated globalPaletteBits is no longer in use, use {@link #readDataPalette(ByteBuf, PaletteType)} instead.
1351-
*/
1352-
@Deprecated(forRemoval = true)
1353-
public static DataPalette readDataPalette(ByteBuf buf, PaletteType paletteType, int globalPaletteBits) {
1354-
return MinecraftTypes.readDataPalette(buf, paletteType);
1346+
return DataPalette.create(palette, storage, paletteType, registrySize);
13551347
}
13561348

13571349
public static void writeDataPalette(ByteBuf buf, DataPalette palette) {
@@ -1388,25 +1380,17 @@ private static Palette readPalette(ByteBuf buf, PaletteType paletteType, int bit
13881380
}
13891381
}
13901382

1391-
public static ChunkSection readChunkSection(ByteBuf buf) {
1383+
public static ChunkSection readChunkSection(ByteBuf buf, int blockStateRegistrySize, int biomeRegistrySize) {
13921384
int blockCount = buf.readShort();
13931385

1394-
DataPalette chunkPalette = MinecraftTypes.readDataPalette(buf, PaletteType.CHUNK);
1395-
DataPalette biomePalette = MinecraftTypes.readDataPalette(buf, PaletteType.BIOME);
1396-
return new ChunkSection(blockCount, chunkPalette, biomePalette);
1397-
}
1398-
1399-
/**
1400-
* @deprecated globalBiomePaletteBits is no longer in use, use {@link #readChunkSection(ByteBuf)} instead.
1401-
*/
1402-
@Deprecated(forRemoval = true)
1403-
public static ChunkSection readChunkSection(ByteBuf buf, int globalBiomePaletteBits) {
1404-
return MinecraftTypes.readChunkSection(buf);
1386+
DataPalette blockStatePalette = MinecraftTypes.readDataPalette(buf, PaletteType.BLOCK_STATE, blockStateRegistrySize);
1387+
DataPalette biomePalette = MinecraftTypes.readDataPalette(buf, PaletteType.BIOME, biomeRegistrySize);
1388+
return new ChunkSection(blockCount, blockStatePalette, biomePalette);
14051389
}
14061390

14071391
public static void writeChunkSection(ByteBuf buf, ChunkSection section) {
14081392
buf.writeShort(section.getBlockCount());
1409-
MinecraftTypes.writeDataPalette(buf, section.getChunkData());
1393+
MinecraftTypes.writeDataPalette(buf, section.getBlockData());
14101394
MinecraftTypes.writeDataPalette(buf, section.getBiomeData());
14111395
}
14121396

protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/chunk/ChunkSection.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,24 @@ public class ChunkSection {
1717
private static final int AIR = 0;
1818

1919
private int blockCount;
20-
private @NonNull DataPalette chunkData;
20+
private @NonNull DataPalette blockData;
2121
@Getter
2222
private @NonNull DataPalette biomeData;
2323

24-
public ChunkSection() {
25-
this(0, DataPalette.createForChunk(), DataPalette.createForBiome());
24+
public ChunkSection(int initialBlockState, int blockStateRegistrySize, int initialBiome, int biomeRegistrySize) {
25+
this(0, DataPalette.createForBlockState(initialBlockState, blockStateRegistrySize), DataPalette.createForBiome(initialBiome, biomeRegistrySize));
2626
}
2727

2828
public ChunkSection(ChunkSection original) {
29-
this(original.blockCount, new DataPalette(original.chunkData), new DataPalette(original.biomeData));
29+
this(original.blockCount, new DataPalette(original.blockData), new DataPalette(original.biomeData));
3030
}
3131

3232
public int getBlock(int x, int y, int z) {
33-
return this.chunkData.get(x, y, z);
33+
return this.blockData.get(x, y, z);
3434
}
3535

3636
public void setBlock(int x, int y, int z, int state) {
37-
int curr = this.chunkData.set(x, y, z, state);
37+
int curr = this.blockData.set(x, y, z, state);
3838
if (state != AIR && curr == AIR) {
3939
this.blockCount++;
4040
} else if (state == AIR && curr != AIR) {

protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/chunk/DataPalette.java

Lines changed: 22 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package org.geysermc.mcprotocollib.protocol.data.game.chunk;
22

3-
import lombok.AllArgsConstructor;
43
import lombok.EqualsAndHashCode;
54
import lombok.Getter;
65
import lombok.NonNull;
7-
import lombok.Setter;
86
import lombok.ToString;
97
import org.geysermc.mcprotocollib.protocol.data.game.chunk.palette.GlobalPalette;
108
import org.geysermc.mcprotocollib.protocol.data.game.chunk.palette.ListPalette;
@@ -14,72 +12,43 @@
1412
import org.geysermc.mcprotocollib.protocol.data.game.chunk.palette.SingletonPalette;
1513

1614
@Getter
17-
@Setter
18-
@AllArgsConstructor
1915
@EqualsAndHashCode
2016
@ToString
2117
public class DataPalette {
22-
23-
/*
24-
* @deprecated globalPaletteBits is no longer in use.
25-
*/
26-
@Deprecated(forRemoval = true)
27-
public static final int GLOBAL_PALETTE_BITS_PER_ENTRY = 14;
18+
private static final double LOG_2 = Math.log(2.0);
2819

2920
private @NonNull Palette palette;
3021
private BitStorage storage;
3122
private final PaletteType paletteType;
23+
private final int globalPaletteBitsPerEntry;
3224

33-
/*
34-
* @deprecated globalPaletteBits is no longer in use, use {@link #DataPalette(Palette, BitStorage, PaletteType)} instead.
35-
*/
36-
@Deprecated(forRemoval = true)
37-
public DataPalette(@NonNull Palette palette, BitStorage storage, PaletteType paletteType, int globalPaletteBits) {
38-
this(palette, storage, paletteType);
25+
private DataPalette(@NonNull Palette palette, BitStorage storage, PaletteType paletteType, int globalPaletteBitsPerEntry) {
26+
this.palette = palette;
27+
this.storage = storage;
28+
this.paletteType = paletteType;
29+
this.globalPaletteBitsPerEntry = globalPaletteBitsPerEntry;
3930
}
4031

4132
public DataPalette(DataPalette original) {
42-
this(original.palette.copy(), original.storage == null ? null : new BitStorage(original.storage), original.paletteType);
33+
this(original.palette.copy(), original.storage == null ? null : new BitStorage(original.storage), original.paletteType, original.globalPaletteBitsPerEntry);
4334
}
4435

45-
public static DataPalette createForChunk() {
46-
return createEmpty(PaletteType.CHUNK);
36+
public static DataPalette createForBlockState(int initialState, int blockStateRegistrySize) {
37+
return createEmpty(PaletteType.BLOCK_STATE, initialState, blockStateRegistrySize);
4738
}
4839

49-
/*
50-
* @deprecated globalPaletteBits is no longer in use, use {@link #createForChunk()} instead.
51-
*/
52-
@Deprecated(forRemoval = true)
53-
public static DataPalette createForChunk(int globalPaletteBits) {
54-
return createForChunk();
55-
}
56-
57-
/*
58-
* @deprecated globalPaletteBits is no longer in use, use {@link #createForBiome()} instead.
59-
*/
60-
@Deprecated(forRemoval = true)
61-
public static DataPalette createForBiome(int globalPaletteBits) {
62-
return createForBiome();
40+
public static DataPalette createForBiome(int initialBiome, int biomeRegistrySize) {
41+
return createEmpty(PaletteType.BIOME, initialBiome, biomeRegistrySize);
6342
}
6443

65-
public static DataPalette createForBiome() {
66-
return createEmpty(PaletteType.BIOME);
44+
public static DataPalette createEmpty(PaletteType paletteType, int initial, int registrySize) {
45+
return create(new SingletonPalette(initial), null, paletteType, registrySize);
6746
}
6847

69-
public static DataPalette createEmpty(PaletteType paletteType) {
70-
return new DataPalette(new ListPalette(paletteType.getMinBitsPerEntry()),
71-
new BitStorage(paletteType.getMinBitsPerEntry(), paletteType.getStorageSize()), paletteType);
48+
public static DataPalette create(@NonNull Palette palette, BitStorage storage, PaletteType paletteType, int registrySize) {
49+
return new DataPalette(palette, storage, paletteType, calculateBitsPerEntry(registrySize));
7250
}
7351

74-
/*
75-
* @deprecated globalPaletteBits is no longer in use, use {@link #createEmpty(PaletteType)} instead.
76-
*/
77-
@Deprecated(forRemoval = true)
78-
public static DataPalette createEmpty(PaletteType paletteType, int globalPaletteBits) {
79-
return createEmpty(paletteType);
80-
}
81-
82-
8352
public int get(int x, int y, int z) {
8453
if (storage != null) {
8554
int id = this.storage.get(index(x, y, z));
@@ -115,7 +84,7 @@ private int sanitizeBitsPerEntry(int bitsPerEntry) {
11584
if (bitsPerEntry <= this.paletteType.getMaxBitsPerEntry()) {
11685
return Math.max(this.paletteType.getMinBitsPerEntry(), bitsPerEntry);
11786
} else {
118-
return GLOBAL_PALETTE_BITS_PER_ENTRY;
87+
return globalPaletteBitsPerEntry;
11988
}
12089
}
12190

@@ -149,4 +118,9 @@ private static Palette createPalette(int bitsPerEntry, PaletteType paletteType)
149118
private int index(int x, int y, int z) {
150119
return y << paletteType.getMaxBitsPerEntry() | z << paletteType.getMinBitsPerEntry() | x;
151120
}
121+
122+
private static int calculateBitsPerEntry(int registrySize) {
123+
// Mojmap uses Mth.ceillog2
124+
return (int) Math.ceil(Math.log(registrySize) / LOG_2);
125+
}
152126
}

protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/chunk/palette/PaletteType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
@Getter
66
public enum PaletteType {
77
BIOME(1, 3, 64),
8-
CHUNK(4, 8, 4096);
8+
BLOCK_STATE(4, 8, 4096);
99

1010
private final int minBitsPerEntry;
1111
private final int maxBitsPerEntry;

protocol/src/test/java/org/geysermc/mcprotocollib/protocol/data/ChunkTest.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,25 @@
1919
import static org.junit.jupiter.api.Assertions.assertNotEquals;
2020

2121
public class ChunkTest {
22+
// Arbitrary registry size values
23+
private static final int BLOCK_STATE_REGISTRY_SIZE = 1000;
24+
private static final int BIOME_REGISTRY_SIZE = 100;
25+
2226
private static final Logger log = LoggerFactory.getLogger(ChunkTest.class);
2327
private final List<ChunkSection> chunkSectionsToTest = new ArrayList<>();
2428

2529
@BeforeEach
2630
public void setup() {
27-
chunkSectionsToTest.add(new ChunkSection());
31+
chunkSectionsToTest.add(new ChunkSection(420, BLOCK_STATE_REGISTRY_SIZE, 42, BIOME_REGISTRY_SIZE));
2832

29-
ChunkSection section = new ChunkSection();
33+
ChunkSection section = new ChunkSection(20, BLOCK_STATE_REGISTRY_SIZE, 35, BIOME_REGISTRY_SIZE);
3034
section.setBlock(0, 0, 0, 10);
3135
chunkSectionsToTest.add(section);
3236

3337
SingletonPalette singletonPalette = new SingletonPalette(20);
34-
DataPalette dataPalette = new DataPalette(singletonPalette, null, PaletteType.CHUNK);
35-
DataPalette biomePalette = new DataPalette(singletonPalette, null, PaletteType.BIOME);
36-
section = new ChunkSection(4096, dataPalette, biomePalette);
38+
DataPalette blockPalette = DataPalette.create(singletonPalette, null, PaletteType.BLOCK_STATE, BLOCK_STATE_REGISTRY_SIZE);
39+
DataPalette biomePalette = DataPalette.create(singletonPalette, null, PaletteType.BIOME, BIOME_REGISTRY_SIZE);
40+
section = new ChunkSection(4096, blockPalette, biomePalette);
3741
chunkSectionsToTest.add(section);
3842
}
3943

@@ -44,7 +48,7 @@ public void testChunkSectionEncoding() {
4448
MinecraftTypes.writeChunkSection(buf, section);
4549
ChunkSection decoded;
4650
try {
47-
decoded = MinecraftTypes.readChunkSection(buf);
51+
decoded = MinecraftTypes.readChunkSection(buf, BLOCK_STATE_REGISTRY_SIZE, BIOME_REGISTRY_SIZE);
4852
} catch (Exception e) {
4953
log.error(section.toString(), e);
5054
throw e;

0 commit comments

Comments
 (0)