Implement proper biome palette reading

This commit is contained in:
Camotoy 2021-11-19 18:59:27 -05:00
parent a4267d0fe8
commit a22d016a8e
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
5 changed files with 54 additions and 37 deletions

View file

@ -1,5 +1,6 @@
package com.github.steveice10.mc.protocol.data.game.chunk;
import com.github.steveice10.mc.protocol.data.game.chunk.palette.PaletteType;
import com.github.steveice10.packetlib.io.NetInput;
import com.github.steveice10.packetlib.io.NetOutput;
import lombok.*;
@ -11,8 +12,6 @@ import java.io.IOException;
@AllArgsConstructor
@EqualsAndHashCode
public class ChunkSection {
private static final int MAX_PALETTE_BITS_PER_ENTRY = 8;
private static final int MAX_BIOME_BITS_PER_ENTRY = 2;
private static final int AIR = 0;
@ -22,18 +21,18 @@ public class ChunkSection {
private @NonNull DataPalette biomeData;
public ChunkSection() {
this(0, DataPalette.createForChunk(), DataPalette.createForBiome());
this(0, DataPalette.createForChunk(), DataPalette.createForBiome(4));
}
public static ChunkSection read(NetInput in) throws IOException {
public static ChunkSection read(NetInput in, int globalBiomePaletteBits) throws IOException {
int blockCount = in.readShort();
DataPalette chunkPalette = DataPalette.read(in, MAX_PALETTE_BITS_PER_ENTRY, DataPalette.CHUNK_SIZE);
DataPalette biomePalette = DataPalette.read(in, MAX_BIOME_BITS_PER_ENTRY, DataPalette.BIOME_SIZE);
DataPalette chunkPalette = DataPalette.read(in, PaletteType.CHUNK, DataPalette.GLOBAL_PALETTE_BITS_PER_ENTRY);
DataPalette biomePalette = DataPalette.read(in, PaletteType.BIOME, globalBiomePaletteBits);
return new ChunkSection(blockCount, chunkPalette, biomePalette);
}
public static void write(NetOutput out, ChunkSection section) throws IOException {
public static void write(NetOutput out, ChunkSection section, int globalBiomePaletteBits) throws IOException {
out.writeShort(section.blockCount);
DataPalette.write(out, section.chunkData);
DataPalette.write(out, section.biomeData);

View file

@ -13,43 +13,44 @@ import java.io.IOException;
@EqualsAndHashCode
@ToString
public class DataPalette {
static final int BIOME_SIZE = 64;
static final int CHUNK_SIZE = 4096;
private static final int MAX_BIOME_BITS_PER_ENTRY = 2;
private static final int MIN_PALETTE_BITS_PER_ENTRY = 4;
private static final int MAX_PALETTE_BITS_PER_ENTRY = 8;
private static final int GLOBAL_PALETTE_BITS_PER_ENTRY = 14;
public static final int GLOBAL_PALETTE_BITS_PER_ENTRY = 14;
private @NonNull Palette palette;
private BitStorage storage;
private final int maxBitsForType;
private final int maxStorageSize;
private final PaletteType paletteType;
private final int globalPaletteBits;
public static DataPalette createForChunk() {
return createEmpty(MAX_PALETTE_BITS_PER_ENTRY, CHUNK_SIZE);
return createForChunk(GLOBAL_PALETTE_BITS_PER_ENTRY);
}
public static DataPalette createForBiome() {
return createEmpty(MAX_BIOME_BITS_PER_ENTRY, BIOME_SIZE);
public static DataPalette createForChunk(int globalPaletteBits) {
return createEmpty(PaletteType.CHUNK, globalPaletteBits);
}
public static DataPalette createEmpty(int maxBitsForType, int maxStorageSize) {
public static DataPalette createForBiome(int globalPaletteBits) {
return createEmpty(PaletteType.BIOME, globalPaletteBits);
}
public static DataPalette createEmpty(PaletteType paletteType, int globalPaletteBits) {
return new DataPalette(new ListPalette(MIN_PALETTE_BITS_PER_ENTRY),
new BitStorage(MIN_PALETTE_BITS_PER_ENTRY, maxBitsForType), maxBitsForType, maxStorageSize);
new BitStorage(MIN_PALETTE_BITS_PER_ENTRY, paletteType.getMaxBitsPerEntry()), paletteType, globalPaletteBits);
}
public static DataPalette read(NetInput in, int maxBitsForType, int maxSizeForType) throws IOException {
public static DataPalette read(NetInput in, PaletteType paletteType, int globalPaletteBits) throws IOException {
int bitsPerEntry = in.readByte();
Palette palette = readPalette(bitsPerEntry, maxBitsForType, in);
Palette palette = readPalette(bitsPerEntry, paletteType.getMaxBitsPerEntry(), in);
BitStorage storage;
if (!(palette instanceof SingletonPalette)) {
storage = new BitStorage(bitsPerEntry, maxSizeForType, in.readLongs(in.readVarInt()));
storage = new BitStorage(bitsPerEntry, paletteType.getStorageSize(), in.readLongs(in.readVarInt()));
} else {
in.readVarInt();
storage = null;
}
return new DataPalette(palette, storage, maxBitsForType, maxSizeForType);
return new DataPalette(palette, storage, paletteType, globalPaletteBits);
}
public static void write(NetOutput out, DataPalette palette) throws IOException {
@ -116,7 +117,7 @@ public class DataPalette {
}
private int sanitizeBitsPerEntry(int bitsPerEntry) {
if (bitsPerEntry <= MAX_PALETTE_BITS_PER_ENTRY) {
if (bitsPerEntry <= paletteType.getMaxBitsPerEntry()) {
return Math.max(MIN_PALETTE_BITS_PER_ENTRY, bitsPerEntry);
} else {
return GLOBAL_PALETTE_BITS_PER_ENTRY;
@ -128,25 +129,25 @@ public class DataPalette {
BitStorage oldData = this.storage;
int bitsPerEntry = sanitizeBitsPerEntry(oldPalette instanceof SingletonPalette ? 1 : oldData.getBitsPerEntry() + 1);
this.palette = createPalette(bitsPerEntry);
this.storage = new BitStorage(bitsPerEntry, maxStorageSize);
this.palette = createPalette(bitsPerEntry, paletteType.getMaxBitsPerEntry());
this.storage = new BitStorage(bitsPerEntry, paletteType.getStorageSize());
if (oldPalette instanceof SingletonPalette) {
for (int i = 0; i < maxStorageSize; i++) {
for (int i = 0; i < paletteType.getStorageSize(); i++) {
// TODO necessary?
this.storage.set(i, 0);
}
} else {
for (int i = 0; i < maxStorageSize; i++) {
for (int i = 0; i < paletteType.getStorageSize(); i++) {
this.storage.set(i, this.palette.stateToId(oldPalette.idToState(oldData.get(i))));
}
}
}
private static Palette createPalette(int bitsPerEntry) {
private static Palette createPalette(int bitsPerEntry, int maxBitsPerEntry) {
if (bitsPerEntry <= MIN_PALETTE_BITS_PER_ENTRY) {
return new ListPalette(bitsPerEntry);
} else if (bitsPerEntry <= MAX_PALETTE_BITS_PER_ENTRY) {
} else if (bitsPerEntry <= maxBitsPerEntry) {
return new MapPalette(bitsPerEntry);
} else {
return new GlobalPalette();

View file

@ -0,0 +1,17 @@
package com.github.steveice10.mc.protocol.data.game.chunk.palette;
import lombok.Getter;
@Getter
public enum PaletteType {
BIOME(3, 64),
CHUNK(8, 4096);
private final int maxBitsPerEntry;
private final int storageSize;
PaletteType(int maxBitsPerEntry, int storageSize) {
this.maxBitsPerEntry = maxBitsPerEntry;
this.storageSize = storageSize;
}
}

View file

@ -3,9 +3,8 @@ package com.github.steveice10.mc.protocol.data.game.level.particle;
public enum ParticleType {
AMBIENT_ENTITY_EFFECT,
ANGRY_VILLAGER,
BARRIER,
LIGHT,
BLOCK,
BLOCK_MARKER,
BUBBLE,
CLOUD,
CRIT,
@ -30,7 +29,7 @@ public enum ParticleType {
FIREWORK,
FISHING,
FLAME,
SOUL_FLAME,
SOUL_FIRE_FLAME,
SOUL,
FLASH,
HAPPY_VILLAGER,

View file

@ -2,6 +2,7 @@ package com.github.steveice10.mc.protocol.data;
import com.github.steveice10.mc.protocol.data.game.chunk.ChunkSection;
import com.github.steveice10.mc.protocol.data.game.chunk.DataPalette;
import com.github.steveice10.mc.protocol.data.game.chunk.palette.PaletteType;
import com.github.steveice10.mc.protocol.data.game.chunk.palette.SingletonPalette;
import com.github.steveice10.packetlib.io.stream.StreamNetInput;
import com.github.steveice10.packetlib.io.stream.StreamNetOutput;
@ -27,8 +28,8 @@ public class ChunkTest {
chunkSectionsToTest.add(section);
SingletonPalette singletonPalette = new SingletonPalette(20);
DataPalette dataPalette = new DataPalette(singletonPalette, null, 8, 4096);
DataPalette biomePalette = new DataPalette(singletonPalette, null, 2, 64);
DataPalette dataPalette = new DataPalette(singletonPalette, null, PaletteType.CHUNK, DataPalette.GLOBAL_PALETTE_BITS_PER_ENTRY);
DataPalette biomePalette = new DataPalette(singletonPalette, null, PaletteType.BIOME, 4);
section = new ChunkSection(4096, dataPalette, biomePalette);
chunkSectionsToTest.add(section);
}
@ -38,11 +39,11 @@ public class ChunkTest {
for (ChunkSection section : chunkSectionsToTest) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
StreamNetOutput out = new StreamNetOutput(stream);
ChunkSection.write(out, section);
ChunkSection.write(out, section, 4);
StreamNetInput in = new StreamNetInput(new ByteArrayInputStream(stream.toByteArray()));
ChunkSection decoded;
try {
decoded = ChunkSection.read(in);
decoded = ChunkSection.read(in, 4);
} catch (Exception e) {
System.out.println(section);
e.printStackTrace();