mirror of
https://github.com/GeyserMC/MCProtocolLib.git
synced 2024-12-04 21:01:02 -05:00
Fixed 1.16 chunks and renamed states to palette
This commit is contained in:
parent
b5eb5ca624
commit
3cee923a3f
3 changed files with 60 additions and 102 deletions
|
@ -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.NetInput;
|
||||||
import com.github.steveice10.packetlib.io.NetOutput;
|
import com.github.steveice10.packetlib.io.NetOutput;
|
||||||
import lombok.AccessLevel;
|
import lombok.*;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -22,25 +18,27 @@ public class Chunk {
|
||||||
private int blockCount;
|
private int blockCount;
|
||||||
private int bitsPerEntry;
|
private int bitsPerEntry;
|
||||||
|
|
||||||
private @NonNull List<Integer> states;
|
private @NonNull List<Integer> palette;
|
||||||
private @NonNull FlexibleStorage storage;
|
private @NonNull FlexibleStorage storage;
|
||||||
|
|
||||||
public Chunk() {
|
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 {
|
public static Chunk read(NetInput in) throws IOException {
|
||||||
int blockCount = in.readShort();
|
int blockCount = in.readShort();
|
||||||
int bitsPerEntry = in.readUnsignedByte();
|
int bitsPerEntry = in.readUnsignedByte();
|
||||||
|
|
||||||
List<Integer> states = new ArrayList<>();
|
List<Integer> palette = new ArrayList<>();
|
||||||
int stateCount = bitsPerEntry > 8 || bitsPerEntry == 0 ? 0 : in.readVarInt();
|
if(bitsPerEntry <= 8) {
|
||||||
for(int i = 0; i < stateCount; i++) {
|
int paletteLength = in.readVarInt();
|
||||||
states.add(in.readVarInt());
|
for(int i = 0; i < paletteLength; i++) {
|
||||||
|
palette.add(in.readVarInt());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlexibleStorage storage = new FlexibleStorage(bitsPerEntry, in.readLongs(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 {
|
public static void write(NetOutput out, Chunk chunk) throws IOException {
|
||||||
|
@ -48,8 +46,8 @@ public class Chunk {
|
||||||
out.writeByte(chunk.getBitsPerEntry());
|
out.writeByte(chunk.getBitsPerEntry());
|
||||||
|
|
||||||
if(chunk.getBitsPerEntry() <= 8) {
|
if(chunk.getBitsPerEntry() <= 8) {
|
||||||
out.writeVarInt(chunk.getStates().size());
|
out.writeVarInt(chunk.getPalette().size());
|
||||||
for (int state : chunk.getStates()) {
|
for (int state : chunk.getPalette()) {
|
||||||
out.writeVarInt(state);
|
out.writeVarInt(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,31 +63,28 @@ public class Chunk {
|
||||||
|
|
||||||
public int get(int x, int y, int z) {
|
public int get(int x, int y, int z) {
|
||||||
int id = this.storage.get(index(x, y, 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) {
|
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) {
|
if(id == -1) {
|
||||||
this.states.add(state);
|
this.palette.add(state);
|
||||||
if(this.states.size() > 1 << this.bitsPerEntry) {
|
if(this.palette.size() > 1 << this.bitsPerEntry) {
|
||||||
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) {
|
if(this.bitsPerEntry > 8) {
|
||||||
oldStates = new ArrayList<Integer>(this.states);
|
this.palette.clear();
|
||||||
this.states.clear();
|
this.bitsPerEntry = 14;
|
||||||
this.bitsPerEntry = 13;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FlexibleStorage oldStorage = this.storage;
|
FlexibleStorage oldStorage = this.storage;
|
||||||
this.storage = new FlexibleStorage(this.bitsPerEntry, this.storage.getSize());
|
this.storage = oldStorage.transferData(this.bitsPerEntry, (index) ->
|
||||||
for(int index = 0; index < this.storage.getSize(); index++) {
|
this.bitsPerEntry <= 8 ? oldStorage.get(index) : oldStates.get(index));
|
||||||
this.storage.set(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);
|
int ind = index(x, y, z);
|
||||||
|
|
|
@ -4,6 +4,7 @@ import lombok.Data;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.function.IntFunction;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class FlexibleStorage {
|
public class FlexibleStorage {
|
||||||
|
@ -12,34 +13,32 @@ public class FlexibleStorage {
|
||||||
private final int size;
|
private final int size;
|
||||||
private final long maxEntryValue;
|
private final long maxEntryValue;
|
||||||
|
|
||||||
public FlexibleStorage(int bitsPerEntry, int size) {
|
private final char valuesPerLong;
|
||||||
this(bitsPerEntry, new long[roundToNearest(size * bitsPerEntry, 64) / 64]);
|
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) {
|
public FlexibleStorage(int bitsPerEntry, @NonNull long[] data) {
|
||||||
this.bitsPerEntry = bitsPerEntry;
|
this.bitsPerEntry = bitsPerEntry;
|
||||||
if(bitsPerEntry <= 8) {
|
this.data = Arrays.copyOf(data, data.length);
|
||||||
this.data = padArray(bitsPerEntry, Arrays.copyOf(data, data.length));
|
this.size = data.length * 64 / bitsPerEntry;
|
||||||
} else {
|
this.maxEntryValue = (1L << bitsPerEntry) - 1;
|
||||||
this.data = padArray(bitsPerEntry, 14, Arrays.copyOf(data, data.length));
|
|
||||||
}
|
|
||||||
this.size = data.length * 64 / this.bitsPerEntry;
|
|
||||||
this.maxEntryValue = (1L << this.bitsPerEntry) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int roundToNearest(int value, int roundTo) {
|
this.valuesPerLong = (char) (64 / bitsPerEntry);
|
||||||
if(roundTo == 0) {
|
int expectedLength = (4096 + valuesPerLong - 1) / valuesPerLong;
|
||||||
return 0;
|
if(data.length != expectedLength) {
|
||||||
} else if(value == 0) {
|
throw new IllegalArgumentException("Expected " + expectedLength + " longs but got " + data.length + " longs");
|
||||||
return roundTo;
|
|
||||||
} else {
|
|
||||||
if(value < 0) {
|
|
||||||
roundTo *= -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int remainder = value % roundTo;
|
|
||||||
return remainder != 0 ? value + roundTo - remainder : value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
public int get(int index) {
|
||||||
|
@ -47,16 +46,9 @@ public class FlexibleStorage {
|
||||||
throw new IndexOutOfBoundsException();
|
throw new IndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
|
|
||||||
int bitIndex = index * this.bitsPerEntry;
|
int cellIndex = (int) (index * divideMultiply + divideAdd >> 32L >> divideShift);
|
||||||
int startIndex = bitIndex / 64;
|
int bitIndex = (index - cellIndex * valuesPerLong) * bitsPerEntry;
|
||||||
int endIndex = ((index + 1) * this.bitsPerEntry - 1) / 64;
|
return (int) (data[cellIndex] >> bitIndex & maxEntryValue);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set(int index, int value) {
|
public void set(int index, int value) {
|
||||||
|
@ -68,18 +60,12 @@ public class FlexibleStorage {
|
||||||
throw new IllegalArgumentException("Value cannot be outside of accepted range.");
|
throw new IllegalArgumentException("Value cannot be outside of accepted range.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int bitIndex = index * this.bitsPerEntry;
|
int cellIndex = (int) (index * divideMultiply + divideAdd >> 32L >> divideShift);
|
||||||
int startIndex = bitIndex / 64;
|
int bitIndex = (index - cellIndex * valuesPerLong) * bitsPerEntry;
|
||||||
int endIndex = ((index + 1) * this.bitsPerEntry - 1) / 64;
|
data[cellIndex] &= ~(maxEntryValue << bitIndex) | (value & maxEntryValue) << bitIndex;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
-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, 1, 858993459, 858993459, 0, 715827882, 715827882, 0, 613566756, 613566756,
|
||||||
0, Integer.MIN_VALUE, 0, 2, 477218588, 477218588, 0, 429496729, 429496729, 0,
|
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,
|
70409299, 70409299, 0, 69273666, 69273666, 0, 68174084, 68174084, 0, Integer.MIN_VALUE,
|
||||||
0, 5 };
|
0, 5 };
|
||||||
|
|
||||||
private static long[] padArray(int bitsPerEntry, long[] oldData) {
|
public FlexibleStorage transferData(int newBitsPerEntry, IntFunction<Integer> valueGetter) {
|
||||||
return padArray(bitsPerEntry, bitsPerEntry, oldData);
|
FlexibleStorage newStorage = new FlexibleStorage(newBitsPerEntry);
|
||||||
}
|
for(int i = 0; i < 4096; i++) {
|
||||||
|
newStorage.set(i, valueGetter.apply(i));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
return data;
|
return newStorage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,10 +37,6 @@ public class ServerChunkDataPacket implements Packet {
|
||||||
CompoundTag heightMaps = NBT.read(in);
|
CompoundTag heightMaps = NBT.read(in);
|
||||||
int[] biomeData = fullChunk ? in.readInts(1024) : null;
|
int[] biomeData = fullChunk ? in.readInts(1024) : null;
|
||||||
byte[] data = in.readBytes(in.readVarInt());
|
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));
|
NetInput dataIn = new StreamNetInput(new ByteArrayInputStream(data));
|
||||||
Chunk[] chunks = new Chunk[16];
|
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);
|
this.column = new Column(x, z, ignoreOldData, chunks, tileEntities, heightMaps, biomeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue