2019-08-03 15:25:24 +02:00
|
|
|
package fr.themode.minestom.utils;
|
|
|
|
|
2019-09-06 16:05:36 +02:00
|
|
|
import com.github.simplenet.Client;
|
|
|
|
import com.github.simplenet.packet.Packet;
|
2019-08-22 14:52:32 +02:00
|
|
|
import fr.themode.minestom.chat.Chat;
|
2019-08-13 17:52:09 +02:00
|
|
|
import fr.themode.minestom.item.ItemStack;
|
2019-09-02 06:02:12 +02:00
|
|
|
import fr.themode.minestom.net.ConnectionUtils;
|
2020-02-09 15:34:09 +01:00
|
|
|
import fr.themode.minestom.net.packet.PacketReader;
|
2019-09-06 16:05:36 +02:00
|
|
|
import fr.themode.minestom.utils.buffer.BufferWrapper;
|
2019-09-02 06:02:12 +02:00
|
|
|
import fr.themode.minestom.utils.consumer.StringConsumer;
|
2019-08-03 15:25:24 +02:00
|
|
|
|
|
|
|
import java.io.UnsupportedEncodingException;
|
2020-02-13 15:14:41 +01:00
|
|
|
import java.util.ArrayList;
|
2019-09-02 06:02:12 +02:00
|
|
|
import java.util.function.Consumer;
|
2019-08-03 15:25:24 +02:00
|
|
|
|
|
|
|
public class Utils {
|
|
|
|
|
2019-09-02 06:02:12 +02:00
|
|
|
public static void writeString(Packet packet, String value) {
|
2019-08-03 15:25:24 +02:00
|
|
|
byte[] bytes = new byte[0];
|
|
|
|
try {
|
|
|
|
bytes = value.getBytes("UTF-8");
|
|
|
|
} catch (UnsupportedEncodingException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
if (bytes.length > 32767) {
|
|
|
|
System.out.println("String too big (was " + value.length() + " bytes encoded, max " + 32767 + ")");
|
|
|
|
} else {
|
2019-09-02 06:02:12 +02:00
|
|
|
writeVarInt(packet, bytes.length);
|
|
|
|
packet.putBytes(bytes);
|
2019-08-03 15:25:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-13 15:14:41 +01:00
|
|
|
public static void readStringVarIntSized(Client client, StringConsumer consumer) {
|
2019-09-02 06:02:12 +02:00
|
|
|
ConnectionUtils.readVarInt(client, length -> {
|
|
|
|
int stringLength = Utils.lengthVarInt(length) + length;
|
|
|
|
client.readBytes(length, bytes -> {
|
|
|
|
try {
|
|
|
|
consumer.accept(new String(bytes, "UTF-8"), stringLength);
|
|
|
|
} catch (UnsupportedEncodingException e) {
|
|
|
|
consumer.accept(null, stringLength);
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2019-08-03 15:25:24 +02:00
|
|
|
}
|
|
|
|
|
2020-02-13 15:14:41 +01:00
|
|
|
public static void readStringShortSized(Client client, StringConsumer consumer) {
|
|
|
|
|
|
|
|
client.readShort(length -> {
|
|
|
|
client.readBytes(length, bytes -> {
|
|
|
|
try {
|
|
|
|
consumer.accept(new String(bytes, "UTF-8"), length);
|
|
|
|
} catch (UnsupportedEncodingException e) {
|
|
|
|
consumer.accept(null, length);
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-09-06 16:05:36 +02:00
|
|
|
public static void writeVarIntBuffer(BufferWrapper buffer, int value) {
|
2019-08-03 15:25:24 +02:00
|
|
|
do {
|
|
|
|
byte temp = (byte) (value & 0b01111111);
|
|
|
|
value >>>= 7;
|
|
|
|
if (value != 0) {
|
|
|
|
temp |= 0b10000000;
|
|
|
|
}
|
|
|
|
buffer.putByte(temp);
|
|
|
|
} while (value != 0);
|
|
|
|
}
|
|
|
|
|
2019-09-02 06:02:12 +02:00
|
|
|
public static void writeVarInt(Packet packet, int value) {
|
|
|
|
do {
|
|
|
|
byte temp = (byte) (value & 0b01111111);
|
|
|
|
value >>>= 7;
|
|
|
|
if (value != 0) {
|
|
|
|
temp |= 0b10000000;
|
|
|
|
}
|
|
|
|
packet.putByte(temp);
|
|
|
|
} while (value != 0);
|
|
|
|
}
|
|
|
|
|
2019-08-03 15:25:24 +02:00
|
|
|
public static int lengthVarInt(int value) {
|
|
|
|
int i = 0;
|
|
|
|
do {
|
|
|
|
i++;
|
|
|
|
byte temp = (byte) (value & 0b01111111);
|
|
|
|
value >>>= 7;
|
|
|
|
if (value != 0) {
|
|
|
|
temp |= 0b10000000;
|
|
|
|
}
|
2019-08-07 03:42:48 +02:00
|
|
|
} while (value != 0);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2019-09-02 06:02:12 +02:00
|
|
|
public static void writePosition(Packet packet, int x, int y, int z) {
|
|
|
|
packet.putLong(SerializerUtils.positionToLong(x, y, z));
|
2019-08-18 20:38:09 +02:00
|
|
|
}
|
|
|
|
|
2019-09-02 06:02:12 +02:00
|
|
|
public static void writePosition(Packet packet, BlockPosition blockPosition) {
|
|
|
|
writePosition(packet, blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
|
2019-08-12 08:30:59 +02:00
|
|
|
}
|
|
|
|
|
2019-09-02 06:02:12 +02:00
|
|
|
public static void readPosition(Client client, Consumer<BlockPosition> consumer) {
|
|
|
|
client.readLong(value -> {
|
|
|
|
consumer.accept(SerializerUtils.longToBlockPosition(value));
|
|
|
|
});
|
2019-08-03 15:25:24 +02:00
|
|
|
}
|
|
|
|
|
2019-09-02 06:02:12 +02:00
|
|
|
public static void writeItemStack(Packet packet, ItemStack itemStack) {
|
2020-02-13 15:14:41 +01:00
|
|
|
if (itemStack == null || itemStack.isAir()) {
|
2019-09-02 06:02:12 +02:00
|
|
|
packet.putBoolean(false);
|
2019-08-13 17:52:09 +02:00
|
|
|
} else {
|
2019-09-02 06:02:12 +02:00
|
|
|
packet.putBoolean(true);
|
|
|
|
Utils.writeVarInt(packet, itemStack.getMaterial().getId());
|
|
|
|
packet.putByte(itemStack.getAmount());
|
2019-08-22 14:52:32 +02:00
|
|
|
|
2020-02-13 15:14:41 +01:00
|
|
|
if (!itemStack.hasNbtTag()) {
|
|
|
|
packet.putByte((byte) 0x00); // No nbt
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-09-02 06:02:12 +02:00
|
|
|
packet.putByte((byte) 0x0A); // Compound
|
2020-02-13 15:14:41 +01:00
|
|
|
packet.putShort((short) 0); // Empty compound name
|
2019-08-22 14:52:32 +02:00
|
|
|
|
|
|
|
// Unbreakable
|
|
|
|
if (itemStack.isUnbreakable()) {
|
2019-09-02 06:02:12 +02:00
|
|
|
packet.putByte((byte) 0x03); // Integer
|
|
|
|
packet.putString("Unbreakable");
|
|
|
|
packet.putInt(1);
|
2019-08-22 14:52:32 +02:00
|
|
|
}
|
|
|
|
|
2019-09-06 16:05:36 +02:00
|
|
|
// Damage
|
|
|
|
packet.putByte((byte) 0x02);
|
|
|
|
packet.putString("Damage");
|
|
|
|
packet.putShort(itemStack.getDamage());
|
|
|
|
|
2019-08-22 14:52:32 +02:00
|
|
|
// Display
|
2020-02-13 15:14:41 +01:00
|
|
|
boolean hasDisplayName = itemStack.hasDisplayName();
|
|
|
|
boolean hasLore = itemStack.hasLore();
|
2019-08-22 14:52:32 +02:00
|
|
|
|
2020-02-13 15:14:41 +01:00
|
|
|
if (hasDisplayName || hasLore) {
|
|
|
|
packet.putByte((byte) 0x0A); // Start display compound
|
|
|
|
packet.putString("display");
|
|
|
|
|
|
|
|
if (hasDisplayName) {
|
|
|
|
packet.putByte((byte) 0x08);
|
|
|
|
packet.putString("Name");
|
|
|
|
packet.putString(Chat.legacyTextString(itemStack.getDisplayName()));
|
|
|
|
}
|
2019-08-22 14:52:32 +02:00
|
|
|
|
2020-02-13 15:14:41 +01:00
|
|
|
if (hasLore) {
|
|
|
|
ArrayList<String> lore = itemStack.getLore();
|
2019-08-22 14:52:32 +02:00
|
|
|
|
2020-02-13 15:14:41 +01:00
|
|
|
packet.putByte((byte) 0x09);
|
|
|
|
packet.putString("Lore");
|
|
|
|
packet.putByte((byte) 0x08);
|
|
|
|
packet.putInt(lore.size());
|
|
|
|
for (String line : lore) {
|
|
|
|
packet.putString(Chat.legacyTextString(line));
|
|
|
|
}
|
|
|
|
}
|
2019-08-22 14:52:32 +02:00
|
|
|
|
2020-02-13 15:14:41 +01:00
|
|
|
packet.putByte((byte) 0); // End display compound
|
|
|
|
}
|
|
|
|
// End display
|
2019-09-06 16:05:36 +02:00
|
|
|
|
2019-09-02 06:02:12 +02:00
|
|
|
packet.putByte((byte) 0); // End nbt
|
2019-08-13 17:52:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-09 15:34:09 +01:00
|
|
|
public static void readItemStack(PacketReader reader, Consumer<ItemStack> consumer) {
|
|
|
|
reader.readBoolean(present -> {
|
|
|
|
if (!present) {
|
|
|
|
consumer.accept(ItemStack.AIR_ITEM); // Consume air item if empty
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
reader.readVarInt(id -> {
|
2020-02-16 19:11:36 +01:00
|
|
|
|
|
|
|
if (id == -1) {
|
|
|
|
// Drop mode
|
|
|
|
consumer.accept(ItemStack.AIR_ITEM);
|
|
|
|
}
|
|
|
|
|
2020-02-09 15:34:09 +01:00
|
|
|
reader.readByte(count -> {
|
2020-02-13 15:14:41 +01:00
|
|
|
ItemStack item = new ItemStack(id, count);
|
|
|
|
reader.readByte(nbt -> { // Should be compound start (0x0A) or 0 if there isn't NBT data
|
|
|
|
if (nbt == 0x00) {
|
|
|
|
consumer.accept(item);
|
|
|
|
return;
|
|
|
|
} else if (nbt == 0x0A) {
|
|
|
|
reader.readShort(compoundName -> { // Ignored, should be empty (main compound name)
|
2020-02-16 19:11:36 +01:00
|
|
|
NbtReaderUtils.readItemStackNBT(reader, consumer, item);
|
2020-02-13 15:14:41 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
}
|
2020-02-09 15:34:09 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-09-06 16:05:36 +02:00
|
|
|
public static void writeBlocks(BufferWrapper buffer, short[] blocksId, int bitsPerEntry) {
|
2019-08-21 16:50:52 +02:00
|
|
|
short count = 0;
|
|
|
|
for (short id : blocksId)
|
|
|
|
if (id != 0)
|
|
|
|
count++;
|
|
|
|
|
|
|
|
buffer.putShort(count);
|
2019-08-10 04:16:01 +02:00
|
|
|
buffer.putByte((byte) bitsPerEntry);
|
|
|
|
int[] blocksData = new int[16 * 16 * 16];
|
|
|
|
for (int y = 0; y < 16; y++) {
|
|
|
|
for (int x = 0; x < 16; x++) {
|
|
|
|
for (int z = 0; z < 16; z++) {
|
|
|
|
int sectionIndex = (((y * 16) + x) * 16) + z;
|
|
|
|
int index = y << 8 | z << 4 | x;
|
2019-08-18 20:38:09 +02:00
|
|
|
blocksData[index] = blocksId[sectionIndex];
|
2019-08-10 04:16:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-09-06 16:05:36 +02:00
|
|
|
long[] data = encodeBlocks(blocksData, bitsPerEntry);
|
|
|
|
buffer.putVarInt(data.length);
|
2019-08-10 04:16:01 +02:00
|
|
|
for (int i = 0; i < data.length; i++) {
|
|
|
|
buffer.putLong(data[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static long[] encodeBlocks(int[] blocks, int bitsPerEntry) {
|
|
|
|
long maxEntryValue = (1L << bitsPerEntry) - 1;
|
|
|
|
|
|
|
|
int length = (int) Math.ceil(blocks.length * bitsPerEntry / 64.0);
|
|
|
|
long[] data = new long[length];
|
|
|
|
|
|
|
|
for (int index = 0; index < blocks.length; index++) {
|
|
|
|
int value = blocks[index];
|
|
|
|
int bitIndex = index * bitsPerEntry;
|
|
|
|
int startIndex = bitIndex / 64;
|
|
|
|
int endIndex = ((index + 1) * bitsPerEntry - 1) / 64;
|
|
|
|
int startBitSubIndex = bitIndex % 64;
|
|
|
|
data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | ((long) value & maxEntryValue) << startBitSubIndex;
|
|
|
|
if (startIndex != endIndex) {
|
|
|
|
int endBitSubIndex = 64 - startBitSubIndex;
|
|
|
|
data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & maxEntryValue) >> endBitSubIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2019-08-03 15:25:24 +02:00
|
|
|
}
|