Fixed 1.16 chunks and renamed states to palette

This commit is contained in:
Tim203 2020-06-23 23:58:52 +02:00
parent b5eb5ca624
commit 3cee923a3f
No known key found for this signature in database
GPG key ID: 064EE9F5BF7C3EE8
3 changed files with 60 additions and 102 deletions

View file

@ -2,11 +2,7 @@ package com.github.steveice10.mc.protocol.data.game.chunk;
import com.github.steveice10.packetlib.io.NetInput;
import com.github.steveice10.packetlib.io.NetOutput;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NonNull;
import lombok.Setter;
import lombok.*;
import java.io.IOException;
import java.util.ArrayList;
@ -22,25 +18,27 @@ public class Chunk {
private int blockCount;
private int bitsPerEntry;
private @NonNull List<Integer> states;
private @NonNull List<Integer> palette;
private @NonNull FlexibleStorage storage;
public Chunk() {
this(0, 4, new ArrayList<>(Collections.singletonList(AIR)), new FlexibleStorage(4, 4096));
this(0, 4, new ArrayList<>(Collections.singletonList(AIR)), new FlexibleStorage(4));
}
public static Chunk read(NetInput in) throws IOException {
int blockCount = in.readShort();
int bitsPerEntry = in.readUnsignedByte();
List<Integer> states = new ArrayList<>();
int stateCount = bitsPerEntry > 8 || bitsPerEntry == 0 ? 0 : in.readVarInt();
for(int i = 0; i < stateCount; i++) {
states.add(in.readVarInt());
List<Integer> palette = new ArrayList<>();
if(bitsPerEntry <= 8) {
int paletteLength = in.readVarInt();
for(int i = 0; i < paletteLength; i++) {
palette.add(in.readVarInt());
}
}
FlexibleStorage storage = new FlexibleStorage(bitsPerEntry, in.readLongs(in.readVarInt()));
return new Chunk(blockCount, bitsPerEntry, states, storage);
return new Chunk(blockCount, bitsPerEntry, palette, storage);
}
public static void write(NetOutput out, Chunk chunk) throws IOException {
@ -48,8 +46,8 @@ public class Chunk {
out.writeByte(chunk.getBitsPerEntry());
if(chunk.getBitsPerEntry() <= 8) {
out.writeVarInt(chunk.getStates().size());
for (int state : chunk.getStates()) {
out.writeVarInt(chunk.getPalette().size());
for (int state : chunk.getPalette()) {
out.writeVarInt(state);
}
}
@ -65,31 +63,28 @@ public class Chunk {
public int get(int x, int y, int z) {
int id = this.storage.get(index(x, y, z));
return this.bitsPerEntry <= 8 ? (id >= 0 && id < this.states.size() ? this.states.get(id) : AIR) : id;
return this.bitsPerEntry <= 8 ? (id >= 0 && id < this.palette.size() ? this.palette.get(id) : AIR) : id;
}
public void set(int x, int y, int z, @NonNull int state) {
int id = this.bitsPerEntry <= 8 ? this.states.indexOf(state) : state;
int id = this.bitsPerEntry <= 8 ? this.palette.indexOf(state) : state;
if(id == -1) {
this.states.add(state);
if(this.states.size() > 1 << this.bitsPerEntry) {
this.palette.add(state);
if(this.palette.size() > 1 << this.bitsPerEntry) {
this.bitsPerEntry++;
List<Integer> oldStates = this.states;
final List<Integer> oldStates = this.bitsPerEntry > 8 ? new ArrayList<>(this.palette) : this.palette;
if(this.bitsPerEntry > 8) {
oldStates = new ArrayList<Integer>(this.states);
this.states.clear();
this.bitsPerEntry = 13;
this.palette.clear();
this.bitsPerEntry = 14;
}
FlexibleStorage oldStorage = this.storage;
this.storage = new FlexibleStorage(this.bitsPerEntry, this.storage.getSize());
for(int index = 0; index < this.storage.getSize(); index++) {
this.storage.set(index, this.bitsPerEntry <= 8 ? oldStorage.get(index) : oldStates.get(index));
}
this.storage = oldStorage.transferData(this.bitsPerEntry, (index) ->
this.bitsPerEntry <= 8 ? oldStorage.get(index) : oldStates.get(index));
}
id = this.bitsPerEntry <= 8 ? this.states.indexOf(state) : state;
id = this.bitsPerEntry <= 8 ? this.palette.indexOf(state) : state;
}
int ind = index(x, y, z);

View file

@ -4,6 +4,7 @@ import lombok.Data;
import lombok.NonNull;
import java.util.Arrays;
import java.util.function.IntFunction;
@Data
public class FlexibleStorage {
@ -12,34 +13,32 @@ public class FlexibleStorage {
private final int size;
private final long maxEntryValue;
public FlexibleStorage(int bitsPerEntry, int size) {
this(bitsPerEntry, new long[roundToNearest(size * bitsPerEntry, 64) / 64]);
private final char valuesPerLong;
private final int magicIndex;
private final long divideMultiply;
private final long divideAdd;
private final long divideShift;
public FlexibleStorage(int bitsPerEntry) {
this(bitsPerEntry, new long[(4096 + (64 / bitsPerEntry) - 1) / (64 / bitsPerEntry)]);
}
public FlexibleStorage(int bitsPerEntry, @NonNull long[] data) {
this.bitsPerEntry = bitsPerEntry;
if(bitsPerEntry <= 8) {
this.data = padArray(bitsPerEntry, Arrays.copyOf(data, data.length));
} else {
this.data = padArray(bitsPerEntry, 14, Arrays.copyOf(data, data.length));
}
this.size = data.length * 64 / this.bitsPerEntry;
this.maxEntryValue = (1L << this.bitsPerEntry) - 1;
}
this.data = Arrays.copyOf(data, data.length);
this.size = data.length * 64 / bitsPerEntry;
this.maxEntryValue = (1L << bitsPerEntry) - 1;
private static int roundToNearest(int value, int roundTo) {
if(roundTo == 0) {
return 0;
} else if(value == 0) {
return roundTo;
} else {
if(value < 0) {
roundTo *= -1;
}
int remainder = value % roundTo;
return remainder != 0 ? value + roundTo - remainder : value;
this.valuesPerLong = (char) (64 / bitsPerEntry);
int expectedLength = (4096 + valuesPerLong - 1) / valuesPerLong;
if(data.length != expectedLength) {
throw new IllegalArgumentException("Expected " + expectedLength + " longs but got " + data.length + " longs");
}
this.magicIndex = 3 * (valuesPerLong - 1);
this.divideMultiply = Integer.toUnsignedLong(MAGIC_VALUES[magicIndex]);
this.divideAdd = Integer.toUnsignedLong(MAGIC_VALUES[magicIndex + 1]);
this.divideShift = MAGIC_VALUES[magicIndex + 2];
}
public int get(int index) {
@ -47,16 +46,9 @@ public class FlexibleStorage {
throw new IndexOutOfBoundsException();
}
int bitIndex = index * this.bitsPerEntry;
int startIndex = bitIndex / 64;
int endIndex = ((index + 1) * this.bitsPerEntry - 1) / 64;
int startBitSubIndex = bitIndex % 64;
if(startIndex == endIndex) {
return (int) (this.data[startIndex] >>> startBitSubIndex & this.maxEntryValue);
} else {
int endBitSubIndex = 64 - startBitSubIndex;
return (int) ((this.data[startIndex] >>> startBitSubIndex | this.data[endIndex] << endBitSubIndex) & this.maxEntryValue);
}
int cellIndex = (int) (index * divideMultiply + divideAdd >> 32L >> divideShift);
int bitIndex = (index - cellIndex * valuesPerLong) * bitsPerEntry;
return (int) (data[cellIndex] >> bitIndex & maxEntryValue);
}
public void set(int index, int value) {
@ -68,18 +60,12 @@ public class FlexibleStorage {
throw new IllegalArgumentException("Value cannot be outside of accepted range.");
}
int bitIndex = index * this.bitsPerEntry;
int startIndex = bitIndex / 64;
int endIndex = ((index + 1) * this.bitsPerEntry - 1) / 64;
int startBitSubIndex = bitIndex % 64;
this.data[startIndex] = this.data[startIndex] & ~(this.maxEntryValue << startBitSubIndex) | ((long) value & this.maxEntryValue) << startBitSubIndex;
if(startIndex != endIndex) {
int endBitSubIndex = 64 - startBitSubIndex;
this.data[endIndex] = this.data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & this.maxEntryValue) >> endBitSubIndex;
}
int cellIndex = (int) (index * divideMultiply + divideAdd >> 32L >> divideShift);
int bitIndex = (index - cellIndex * valuesPerLong) * bitsPerEntry;
data[cellIndex] &= ~(maxEntryValue << bitIndex) | (value & maxEntryValue) << bitIndex;
}
private static final int[] MAGIC_CHUNK_VALUES = {
private static final int[] MAGIC_VALUES = {
-1, -1, 0, Integer.MIN_VALUE, 0, 0, 1431655765, 1431655765, 0, Integer.MIN_VALUE,
0, 1, 858993459, 858993459, 0, 715827882, 715827882, 0, 613566756, 613566756,
0, Integer.MIN_VALUE, 0, 2, 477218588, 477218588, 0, 429496729, 429496729, 0,
@ -101,35 +87,11 @@ public class FlexibleStorage {
70409299, 70409299, 0, 69273666, 69273666, 0, 68174084, 68174084, 0, Integer.MIN_VALUE,
0, 5 };
private static long[] padArray(int bitsPerEntry, long[] oldData) {
return padArray(bitsPerEntry, bitsPerEntry, oldData);
}
private static long[] padArray(int bitsPerEntry, int newBitsPerEntry, long[] oldData) {
long maxEntryValue = (1L << bitsPerEntry) - 1;
char valuesPerLong = (char) (64 / newBitsPerEntry);
int magicIndex = (valuesPerLong - 1) * 3;
long divideMultiply = Integer.toUnsignedLong(MAGIC_CHUNK_VALUES[magicIndex]);
long divideAdd = Integer.toUnsignedLong(MAGIC_CHUNK_VALUES[magicIndex + 1]);
int divideShift = MAGIC_CHUNK_VALUES[magicIndex + 2];
long[] data = new long[(4096 + valuesPerLong - 1) / valuesPerLong];
for(int index = 0; index < 4096; index++) {
int bitIndex = index * bitsPerEntry;
int startIndex = bitIndex / 64;
int endIndex = ((index + 1) * bitsPerEntry - 1) / 64;
int startBitSubIndex = bitIndex % 64;
int value;
if(startIndex != endIndex) {
int endBitSubIndex = 64 - startBitSubIndex;
value = (int) ((oldData[startIndex] >>> startBitSubIndex | oldData[endIndex] << endBitSubIndex) & maxEntryValue);
} else {
value = (int) (oldData[startIndex] >>> startBitSubIndex & maxEntryValue);
}
int cellIndex = (int) (index * divideMultiply + divideAdd >> 32L >> divideShift);
int newBitIndex = (index - cellIndex * valuesPerLong) * newBitsPerEntry;
data[cellIndex] = data[cellIndex] & ~(maxEntryValue << newBitIndex) | (value & maxEntryValue) << newBitIndex;
public FlexibleStorage transferData(int newBitsPerEntry, IntFunction<Integer> valueGetter) {
FlexibleStorage newStorage = new FlexibleStorage(newBitsPerEntry);
for(int i = 0; i < 4096; i++) {
newStorage.set(i, valueGetter.apply(i));
}
return data;
return newStorage;
}
}

View file

@ -37,10 +37,6 @@ public class ServerChunkDataPacket implements Packet {
CompoundTag heightMaps = NBT.read(in);
int[] biomeData = fullChunk ? in.readInts(1024) : null;
byte[] data = in.readBytes(in.readVarInt());
CompoundTag[] tileEntities = new CompoundTag[in.readVarInt()];
for(int i = 0; i < tileEntities.length; i++) {
tileEntities[i] = NBT.read(in);
}
NetInput dataIn = new StreamNetInput(new ByteArrayInputStream(data));
Chunk[] chunks = new Chunk[16];
@ -50,6 +46,11 @@ public class ServerChunkDataPacket implements Packet {
}
}
CompoundTag[] tileEntities = new CompoundTag[in.readVarInt()];
for(int i = 0; i < tileEntities.length; i++) {
tileEntities[i] = NBT.read(in);
}
this.column = new Column(x, z, ignoreOldData, chunks, tileEntities, heightMaps, biomeData);
}