Initial non-working 1.18 commit

Signed-off-by: TheMode <themode@outlook.fr>
This commit is contained in:
TheMode 2021-10-20 21:31:59 +02:00
parent 83ab75d1bf
commit d3b55700e2
11 changed files with 196 additions and 318 deletions

View File

@ -54,8 +54,8 @@ public final class MinecraftServer {
public final static Logger LOGGER = LoggerFactory.getLogger(MinecraftServer.class);
public static final String VERSION_NAME = "1.17.1";
public static final int PROTOCOL_VERSION = 756;
public static final String VERSION_NAME = "21w42a";
public static final int PROTOCOL_VERSION = 1073741870;
// Threads
public static final String THREAD_NAME_BENCHMARK = "Ms-Benchmark";

View File

@ -291,7 +291,8 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
// Recipes end
// Tags
this.playerConnection.sendPacket(TagsPacket.DEFAULT_TAGS);
// FIXME: 1.18
//this.playerConnection.sendPacket(TagsPacket.DEFAULT_TAGS);
// Some client updates
this.playerConnection.sendPacket(getPropertiesPacket()); // Send default properties

View File

@ -11,6 +11,8 @@ import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.network.packet.server.CachedPacket;
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
import net.minestom.server.network.packet.server.play.UpdateLightPacket;
import net.minestom.server.network.packet.server.play.data.ChunkPacketData;
import net.minestom.server.network.packet.server.play.data.LightPacketData;
import net.minestom.server.utils.ArrayUtils;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.Utils;
@ -20,10 +22,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
/**
* Represents a {@link Chunk} which store each individual block in memory.
@ -125,14 +124,14 @@ public class DynamicChunk extends Chunk {
@Override
public void sendChunk(@NotNull Player player) {
if (!isLoaded()) return;
player.sendPackets(lightCache, chunkCache);
player.sendPacket(chunkCache.retrieve());
}
@Override
public void sendChunk() {
if (!isLoaded()) return;
if (getViewers().isEmpty()) return;
sendPacketsToViewers(lightCache, chunkCache);
sendPacketToViewers(chunkCache.retrieve());
}
@NotNull
@ -153,42 +152,49 @@ public class DynamicChunk extends Chunk {
}
private synchronized @NotNull ChunkDataPacket createChunkPacket() {
ChunkDataPacket packet = new ChunkDataPacket();
packet.biomes = biomes;
packet.chunkX = chunkX;
packet.chunkZ = chunkZ;
packet.sections = sectionMap.clone(); // TODO deep clone
packet.entries = entries.clone();
final NBTCompound heightmapsNBT;
// TODO: don't hardcode heightmaps
// Heightmap
int dimensionHeight = getInstance().getDimensionType().getHeight();
int[] motionBlocking = new int[16 * 16];
int[] worldSurface = new int[16 * 16];
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
motionBlocking[x + z * 16] = 0;
worldSurface[x + z * 16] = dimensionHeight - 1;
{
int dimensionHeight = getInstance().getDimensionType().getHeight();
int[] motionBlocking = new int[16 * 16];
int[] worldSurface = new int[16 * 16];
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
motionBlocking[x + z * 16] = 0;
worldSurface[x + z * 16] = dimensionHeight - 1;
}
}
final int bitsForHeight = MathUtils.bitsToRepresent(dimensionHeight);
heightmapsNBT = new NBTCompound()
.setLongArray("MOTION_BLOCKING", Utils.encodeBlocks(motionBlocking, bitsForHeight))
.setLongArray("WORLD_SURFACE", Utils.encodeBlocks(worldSurface, bitsForHeight));
}
final int bitsForHeight = MathUtils.bitsToRepresent(dimensionHeight);
packet.heightmapsNBT = new NBTCompound()
.setLongArray("MOTION_BLOCKING", Utils.encodeBlocks(motionBlocking, bitsForHeight))
.setLongArray("WORLD_SURFACE", Utils.encodeBlocks(worldSurface, bitsForHeight));
ChunkDataPacket packet = new ChunkDataPacket();
packet.chunkX = chunkX;
packet.chunkZ = chunkZ;
// TODO deep clone sections
packet.chunkData = new ChunkPacketData(heightmapsNBT, sectionMap, entries);
packet.lightData = createLightData();
return packet;
}
private synchronized @NotNull UpdateLightPacket createLightPacket() {
List<byte[]> skyLights = new ArrayList<>();
List<byte[]> blockLights = new ArrayList<>();
UpdateLightPacket updateLightPacket = new UpdateLightPacket();
updateLightPacket.chunkX = getChunkX();
updateLightPacket.chunkZ = getChunkZ();
updateLightPacket.lightData = createLightData();
return updateLightPacket;
}
updateLightPacket.skyLight = skyLights;
updateLightPacket.blockLight = blockLights;
private LightPacketData createLightData() {
BitSet skyMask = new BitSet();
BitSet blockMask = new BitSet();
BitSet emptySkyMask = new BitSet();
BitSet emptyBlockMask = new BitSet();
List<byte[]> skyLights = new ArrayList<>();
List<byte[]> blockLights = new ArrayList<>();
final var sections = getSections();
for (var entry : sections.entrySet()) {
@ -200,14 +206,17 @@ public class DynamicChunk extends Chunk {
if (!ArrayUtils.empty(skyLight)) {
skyLights.add(skyLight);
updateLightPacket.skyLightMask.set(index);
skyMask.set(index);
}
if (!ArrayUtils.empty(blockLight)) {
blockLights.add(blockLight);
updateLightPacket.blockLightMask.set(index);
blockMask.set(index);
}
}
return updateLightPacket;
return new LightPacketData(true,
skyMask, blockMask,
emptySkyMask, emptyBlockMask,
skyLights, blockLights);
}
private @Nullable Section getOptionalSection(int y) {

View File

@ -4,6 +4,8 @@ import it.unimi.dsi.fastutil.shorts.Short2ShortOpenHashMap;
import net.minestom.server.MinecraftServer;
import net.minestom.server.instance.Chunk;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.binary.Writeable;
import net.minestom.server.utils.clone.PublicCloneable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@ -16,7 +18,7 @@ import static net.minestom.server.instance.Chunk.CHUNK_SECTION_SIZE;
* 0 is always interpreted as being air, reason being that the block array will be filled with it during initialization.
*/
@ApiStatus.Internal
public final class Palette implements PublicCloneable<Palette> {
public final class Palette implements Writeable, PublicCloneable<Palette> {
/**
* The maximum bits per entry value.
@ -286,6 +288,26 @@ public final class Palette implements PublicCloneable<Palette> {
return bitsPerEntry;
}
@Override
public void write(@NotNull BinaryWriter writer) {
writer.writeByte((byte) bitsPerEntry);
// Palette
if (bitsPerEntry < 9) {
// Palette has to exist
final short[] paletteBlockArray = getPaletteBlockArray();
final int paletteSize = getLastPaletteIndex() + 1;
writer.writeVarInt(paletteSize);
for (int i = 0; i < paletteSize; i++) {
writer.writeVarInt(paletteBlockArray[i]);
}
}
// Raw
writer.writeVarInt(blocks.length);
for (long datum : blocks) {
writer.writeLong(datum);
}
}
@Override
public @NotNull Palette clone() {
try {

View File

@ -95,20 +95,21 @@ public class ServerPacketIdentifier {
public static final int SET_PASSENGERS = 0x54;
public static final int TEAMS = 0x55;
public static final int UPDATE_SCORE = 0x56;
public static final int SET_TITLE_SUBTITLE = 0x57;
public static final int TIME_UPDATE = 0x58;
public static final int SET_TITLE_TEXT = 0x59;
public static final int SET_TITLE_TIME = 0x5A;
public static final int ENTITY_SOUND_EFFECT = 0x5B;
public static final int SOUND_EFFECT = 0x5C;
public static final int STOP_SOUND = 0x5D;
public static final int PLAYER_LIST_HEADER_AND_FOOTER = 0x5E;
public static final int NBT_QUERY_RESPONSE = 0x5F;
public static final int COLLECT_ITEM = 0x60;
public static final int ENTITY_TELEPORT = 0x61;
public static final int ADVANCEMENTS = 0x62;
public static final int ENTITY_PROPERTIES = 0x63;
public static final int ENTITY_EFFECT = 0x64;
public static final int DECLARE_RECIPES = 0x65;
public static final int TAGS = 0x66;
public static final int SET_SIMULATION_DISTANCE = 0x57;
public static final int SET_TITLE_SUBTITLE = 0x58;
public static final int TIME_UPDATE = 0x59;
public static final int SET_TITLE_TEXT = 0x5A;
public static final int SET_TITLE_TIME = 0x5B;
public static final int ENTITY_SOUND_EFFECT = 0x5C;
public static final int SOUND_EFFECT = 0x5D;
public static final int STOP_SOUND = 0x5E;
public static final int PLAYER_LIST_HEADER_AND_FOOTER = 0x5F;
public static final int NBT_QUERY_RESPONSE = 0x60;
public static final int COLLECT_ITEM = 0x61;
public static final int ENTITY_TELEPORT = 0x62;
public static final int ADVANCEMENTS = 0x63;
public static final int ENTITY_PROPERTIES = 0x64;
public static final int ENTITY_EFFECT = 0x65;
public static final int DECLARE_RECIPES = 0x66;
public static final int TAGS = 0x67;
}

View File

@ -1,40 +1,17 @@
package net.minestom.server.network.packet.server.play;
import it.unimi.dsi.fastutil.ints.Int2LongRBTreeMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minestom.server.MinecraftServer;
import net.minestom.server.instance.Section;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.instance.palette.Palette;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.tag.Tag;
import net.minestom.server.utils.PacketUtils;
import net.minestom.server.utils.Utils;
import net.minestom.server.network.packet.server.play.data.ChunkPacketData;
import net.minestom.server.network.packet.server.play.data.LightPacketData;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.world.biomes.Biome;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.*;
public class ChunkDataPacket implements ServerPacket {
public Biome[] biomes;
public int chunkX, chunkZ;
public Map<Integer, Section> sections = new HashMap<>();
public Map<Integer, Block> entries = new HashMap<>();
private static final byte CHUNK_SECTION_COUNT = 16;
public NBTCompound heightmapsNBT = new NBTCompound();
public ChunkPacketData chunkData;
public LightPacketData lightData;
public ChunkDataPacket() {
}
@ -43,159 +20,15 @@ public class ChunkDataPacket implements ServerPacket {
public void write(@NotNull BinaryWriter writer) {
writer.writeInt(chunkX);
writer.writeInt(chunkZ);
ByteBuffer blocks = PacketUtils.localBuffer();
Int2LongRBTreeMap maskMap = new Int2LongRBTreeMap();
for (var entry : sections.entrySet()) {
final int index = entry.getKey();
final Section section = entry.getValue();
final int lengthIndex = index % 64;
final int maskIndex = index / 64;
long mask = maskMap.get(maskIndex);
mask |= 1L << lengthIndex;
maskMap.put(maskIndex, mask);
Utils.writePaletteBlocks(blocks, section.getPalette());
}
final int maskSize = maskMap.size();
writer.writeVarInt(maskSize);
for (int i = 0; i < maskSize; i++) {
final long value = maskMap.getOrDefault(i, 0);
writer.writeLong(value);
}
// Heightmap
writer.writeNBT("", heightmapsNBT);
// Biomes
if (biomes == null || biomes.length == 0) {
writer.writeVarInt(0);
} else {
writer.writeVarInt(biomes.length);
for (Biome biome : biomes) {
writer.writeVarInt(biome.getId());
}
}
// Data
writer.writeVarInt(blocks.position());
writer.write(blocks);
// Block entities
if (entries == null || entries.isEmpty()) {
writer.writeVarInt(0);
} else {
List<NBTCompound> compounds = new ArrayList<>();
for (var entry : entries.entrySet()) {
final int index = entry.getKey();
final Block block = entry.getValue();
final String blockEntity = block.registry().blockEntity();
if (blockEntity == null) continue; // Only send block entities to client
NBTCompound resultNbt = new NBTCompound();
// Append handler tags
final BlockHandler handler = block.handler();
if (handler != null) {
final NBTCompound blockNbt = Objects.requireNonNullElseGet(block.nbt(), NBTCompound::new);
for (Tag<?> tag : handler.getBlockEntityTags()) {
final var value = tag.read(blockNbt);
if (value != null) {
// Tag is present and valid
tag.writeUnsafe(resultNbt, value);
}
}
} else {
// Complete nbt shall be sent if the block has no handler
// Necessary to support all vanilla blocks
final NBTCompound blockNbt = block.nbt();
if (blockNbt != null) resultNbt = blockNbt;
}
// Add block entity
final var blockPosition = ChunkUtils.getBlockPosition(index, chunkX, chunkZ);
resultNbt.setString("id", blockEntity)
.setInt("x", blockPosition.blockX())
.setInt("y", blockPosition.blockY())
.setInt("z", blockPosition.blockZ());
compounds.add(resultNbt);
}
writer.writeVarInt(compounds.size());
compounds.forEach(nbtCompound -> writer.writeNBT("", nbtCompound));
}
this.chunkData.write(writer);
this.lightData.write(writer);
}
@Override
public void read(@NotNull BinaryReader reader) {
this.chunkX = reader.readInt();
this.chunkZ = reader.readInt();
int maskCount = reader.readVarInt();
long[] masks = new long[maskCount];
for (int i = 0; i < maskCount; i++) {
masks[i] = reader.readLong();
}
try {
// TODO: Use heightmaps
// unused at the moment
this.heightmapsNBT = (NBTCompound) reader.readTag();
// Biomes
int[] biomesIds = reader.readVarIntArray();
this.biomes = new Biome[biomesIds.length];
for (int i = 0; i < biomesIds.length; i++) {
this.biomes[i] = MinecraftServer.getBiomeManager().getById(biomesIds[i]);
}
// Data
this.sections = new HashMap<>();
int blockArrayLength = reader.readVarInt();
if (maskCount > 0) {
final long mask = masks[0]; // TODO support for variable size
for (int sectionIndex = 0; sectionIndex < CHUNK_SECTION_COUNT; sectionIndex++) {
final boolean hasSection = (mask & 1 << sectionIndex) != 0;
if (!hasSection) continue;
final Section section = sections.computeIfAbsent(sectionIndex, i -> new Section());
final Palette palette = section.getPalette();
final short blockCount = reader.readShort();
palette.setBlockCount(blockCount);
final byte bitsPerEntry = reader.readByte();
// Resize palette if necessary
if (bitsPerEntry > palette.getBitsPerEntry()) {
palette.resize(bitsPerEntry);
}
// Retrieve palette values
if (bitsPerEntry < 9) {
int paletteSize = reader.readVarInt();
for (int i = 0; i < paletteSize; i++) {
final int paletteValue = reader.readVarInt();
palette.getPaletteBlockArray()[i] = (short) paletteValue;
palette.getBlockPaletteMap().put((short) paletteValue, (short) i);
}
}
// Read blocks
palette.setBlocks(reader.readLongArray());
}
}
// Block entities
final int blockEntityCount = reader.readVarInt();
this.entries = new Int2ObjectOpenHashMap<>(blockEntityCount);
for (int i = 0; i < blockEntityCount; i++) {
NBTCompound tag = (NBTCompound) reader.readTag();
final String id = tag.getString("id");
final BlockHandler handler = MinecraftServer.getBlockManager().getHandlerOrDummy(id);
final int x = tag.getInt("x");
final int y = tag.getInt("y");
final int z = tag.getInt("z");
// TODO add to handlerMap & nbtMap
}
} catch (IOException | NBTException e) {
MinecraftServer.getExceptionManager().handleException(e);
// TODO: should we throw to avoid an invalid packet?
}
// TODO read
}
@Override

View File

@ -24,6 +24,7 @@ public class JoinGamePacket implements ServerPacket {
public long hashedSeed;
public int maxPlayers = 0; // Unused
public int viewDistance;
public int simulationViewDistance = 8;
public boolean reducedDebugInfo = false;
public boolean enableRespawnScreen = true;
public boolean isDebug = false;
@ -63,6 +64,7 @@ public class JoinGamePacket implements ServerPacket {
writer.writeLong(hashedSeed);
writer.writeVarInt(maxPlayers);
writer.writeVarInt(viewDistance);
writer.writeVarInt(simulationViewDistance);
writer.writeBoolean(reducedDebugInfo);
writer.writeBoolean(enableRespawnScreen);
//debug

View File

@ -2,29 +2,16 @@ package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.network.packet.server.play.data.LightPacketData;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
public class UpdateLightPacket implements ServerPacket {
public int chunkX;
public int chunkZ;
//todo make changeable
public boolean trustEdges = true;
public BitSet skyLightMask = new BitSet();
public BitSet blockLightMask = new BitSet();
public BitSet emptySkyLightMask = new BitSet();
public BitSet emptyBlockLightMask = new BitSet();
public List<byte[]> skyLight = new ArrayList<>();
public List<byte[]> blockLight = new ArrayList<>();
public LightPacketData lightData;
/**
* Default constructor, required for reflection operations.
@ -37,25 +24,7 @@ public class UpdateLightPacket implements ServerPacket {
writer.writeVarInt(chunkX);
writer.writeVarInt(chunkZ);
writer.writeBoolean(trustEdges);
writer.writeLongArray(skyLightMask.toLongArray());
writer.writeLongArray(blockLightMask.toLongArray());
writer.writeLongArray(emptySkyLightMask.toLongArray());
writer.writeLongArray(emptyBlockLightMask.toLongArray());
writer.writeVarInt(skyLight.size());
for (byte[] bytes : skyLight) {
writer.writeVarInt(2048); // Always 2048 length
writer.writeBytes(bytes);
}
writer.writeVarInt(blockLight.size());
for (byte[] bytes : blockLight) {
writer.writeVarInt(2048); // Always 2048 length
writer.writeBytes(bytes);
}
this.lightData.write(writer);
}
@Override
@ -63,38 +32,7 @@ public class UpdateLightPacket implements ServerPacket {
chunkX = reader.readVarInt();
chunkZ = reader.readVarInt();
trustEdges = reader.readBoolean();
skyLightMask = BitSet.valueOf(reader.readLongArray());
blockLightMask = BitSet.valueOf(reader.readLongArray());
emptySkyLightMask = BitSet.valueOf(reader.readLongArray());
emptyBlockLightMask = BitSet.valueOf(reader.readLongArray());
// sky light
skyLight.clear();
final int skyLightCount = reader.readVarInt();
for (int i = 0; i < skyLightCount; i++) {
int length = reader.readVarInt();
if (length != 2048) {
throw new IllegalStateException("Length must be 2048.");
}
byte[] bytes = reader.readBytes(length);
skyLight.add(bytes);
}
// block light
blockLight.clear();
final int blockLightCount = reader.readVarInt();
for (int i = 0; i < blockLightCount; i++) {
int length = reader.readVarInt();
if (length != 2048) {
throw new IllegalStateException("Length must be 2048.");
}
byte[] bytes = reader.readBytes(length);
blockLight.add(bytes);
}
// TODO read light data
}
@Override

View File

@ -0,0 +1,44 @@
package net.minestom.server.network.packet.server.play.data;
import net.minestom.server.instance.Section;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.palette.Palette;
import net.minestom.server.utils.PacketUtils;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.binary.Writeable;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.Objects;
public final class ChunkPacketData implements Writeable {
private final NBTCompound heightmaps;
private final Map<Integer, Section> sections;
private final Map<Integer, Block> blockEntities;
public ChunkPacketData(NBTCompound heightmaps, Map<Integer, Section> sections, Map<Integer, Block> blockEntities) {
this.heightmaps = heightmaps.deepClone();
this.sections = Map.copyOf(sections);
this.blockEntities = Map.copyOf(blockEntities);
}
@Override
public void write(@NotNull BinaryWriter writer) {
writer.writeNBT("", this.heightmaps);
// Data
ByteBuffer localBuffer = PacketUtils.localBuffer();
for (int i = 0; i < 0; i++) { // FIXME: palettes
final Section section = Objects.requireNonNullElseGet(sections.get(i), Section::new);
final Palette blockPalette = section.getPalette();
writer.writeShort(blockPalette.getBlockCount());
blockPalette.write(writer); // Blocks
new Palette(2, 2).write(writer); // Biomes
}
writer.writeVarInt(localBuffer.position());
writer.write(localBuffer);
// Block entities
writer.writeVarInt(0);
}
}

View File

@ -0,0 +1,54 @@
package net.minestom.server.network.packet.server.play.data;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.binary.Writeable;
import org.jetbrains.annotations.NotNull;
import java.util.BitSet;
import java.util.List;
public final class LightPacketData implements Writeable {
private final boolean trustEdges;
private final BitSet skyMask;
private final BitSet blockMask;
private final BitSet emptySkyMask;
private final BitSet emptyBlockMask;
private final List<byte[]> skyLight;
private final List<byte[]> blockLight;
public LightPacketData(boolean trustEdges,
BitSet skyMask, BitSet blockMask,
BitSet emptySkyMask, BitSet emptyBlockMask,
List<byte[]> skyLight, List<byte[]> blockLight) {
this.trustEdges = trustEdges;
this.skyMask = skyMask;
this.blockMask = blockMask;
this.emptySkyMask = emptySkyMask;
this.emptyBlockMask = emptyBlockMask;
this.skyLight = skyLight;
this.blockLight = blockLight;
}
@Override
public void write(@NotNull BinaryWriter writer) {
writer.writeBoolean(trustEdges);
writer.writeLongArray(skyMask.toLongArray());
writer.writeLongArray(blockMask.toLongArray());
writer.writeLongArray(emptySkyMask.toLongArray());
writer.writeLongArray(emptyBlockMask.toLongArray());
writer.writeVarInt(skyLight.size());
for (byte[] bytes : skyLight) {
writer.writeVarInt(2048); // Always 2048 length
writer.writeBytes(bytes);
}
writer.writeVarInt(blockLight.size());
for (byte[] bytes : blockLight) {
writer.writeVarInt(2048); // Always 2048 length
writer.writeBytes(bytes);
}
}
}

View File

@ -1,6 +1,5 @@
package net.minestom.server.utils;
import net.minestom.server.instance.palette.Palette;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@ -110,31 +109,6 @@ public final class Utils {
return new UUID(uuidMost, uuidLeast);
}
public static void writePaletteBlocks(ByteBuffer buffer, Palette palette) {
final short blockCount = palette.getBlockCount();
final int bitsPerEntry = palette.getBitsPerEntry();
buffer.putShort(blockCount);
buffer.put((byte) bitsPerEntry);
// Palette
if (bitsPerEntry < 9) {
// Palette has to exist
final short[] paletteBlockArray = palette.getPaletteBlockArray();
final int paletteSize = palette.getLastPaletteIndex() + 1;
writeVarInt(buffer, paletteSize);
for (int i = 0; i < paletteSize; i++) {
writeVarInt(buffer, paletteBlockArray[i]);
}
}
final long[] blocks = palette.getBlocks();
writeVarInt(buffer, blocks.length);
for (long datum : blocks) {
buffer.putLong(datum);
}
}
private static final int[] MAGIC = {
-1, -1, 0, Integer.MIN_VALUE, 0, 0, 1431655765, 1431655765, 0, Integer.MIN_VALUE,
0, 1, 858993459, 858993459, 0, 715827882, 715827882, 0, 613566756, 613566756,