mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-29 04:28:21 +01:00
Remove old NBT code, use Hephaistos
This commit is contained in:
parent
c061e2a71f
commit
4f4d48df92
@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'net.ltgt.apt' version '0.10'
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.3.72'
|
||||
}
|
||||
|
||||
allprojects {
|
||||
@ -71,4 +72,6 @@ dependencies {
|
||||
// Pathfinding
|
||||
implementation 'com.github.MadMartian:hydrazine-path-finding:1.1.0'
|
||||
|
||||
api "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
api 'com.github.jglrxavpok:Hephaistos:v1.0.3'
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit bf55e7257113471e1d6a8116e83edb6cf5011cca
|
||||
Subproject commit 6e5241db3b4546242d2056b27691e9f7c11dc2d5
|
@ -9,12 +9,18 @@ import net.minestom.server.benchmark.BenchmarkManager;
|
||||
import net.minestom.server.command.CommandManager;
|
||||
import net.minestom.server.data.DataManager;
|
||||
import net.minestom.server.entity.EntityManager;
|
||||
import net.minestom.server.entity.EntityType;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.extras.mojangAuth.MojangCrypt;
|
||||
import net.minestom.server.fluids.Fluid;
|
||||
import net.minestom.server.gamedata.loottables.LootTableManager;
|
||||
import net.minestom.server.gamedata.tags.TagManager;
|
||||
import net.minestom.server.instance.Biome;
|
||||
import net.minestom.server.instance.InstanceManager;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.block.BlockManager;
|
||||
import net.minestom.server.item.Enchantment;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.listener.manager.PacketListenerManager;
|
||||
import net.minestom.server.network.ConnectionManager;
|
||||
import net.minestom.server.network.PacketProcessor;
|
||||
@ -22,10 +28,14 @@ import net.minestom.server.network.PacketWriterUtils;
|
||||
import net.minestom.server.network.netty.NettyServer;
|
||||
import net.minestom.server.network.packet.server.play.PluginMessagePacket;
|
||||
import net.minestom.server.network.packet.server.play.ServerDifficultyPacket;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.ping.ResponseDataConsumer;
|
||||
import net.minestom.server.potion.PotionType;
|
||||
import net.minestom.server.recipe.RecipeManager;
|
||||
import net.minestom.server.registry.ResourceGatherer;
|
||||
import net.minestom.server.scoreboard.TeamManager;
|
||||
import net.minestom.server.sound.Sound;
|
||||
import net.minestom.server.stat.StatisticType;
|
||||
import net.minestom.server.storage.StorageFolder;
|
||||
import net.minestom.server.storage.StorageManager;
|
||||
import net.minestom.server.timer.SchedulerManager;
|
||||
@ -115,6 +125,21 @@ public class MinecraftServer {
|
||||
private static MinecraftSessionService sessionService = authService.createMinecraftSessionService();
|
||||
|
||||
public static MinecraftServer init() {
|
||||
// warmup/force-init registries
|
||||
// without this line, registry types that are not loaded explicitly will have an internal empty registry in Registries
|
||||
// That can happen with PotionType for instance, if no code tries to access a PotionType field
|
||||
// TODO: automate (probably with code generation)
|
||||
Block.values();
|
||||
Material.values();
|
||||
PotionType.values();
|
||||
Enchantment.values();
|
||||
EntityType.values();
|
||||
Sound.values();
|
||||
Particle.values();
|
||||
StatisticType.values();
|
||||
Biome.values();
|
||||
Fluid.values();
|
||||
|
||||
connectionManager = new ConnectionManager();
|
||||
packetProcessor = new PacketProcessor();
|
||||
packetListenerManager = new PacketListenerManager();
|
||||
|
@ -5,6 +5,7 @@ import net.minestom.server.inventory.Inventory;
|
||||
import net.minestom.server.inventory.InventoryType;
|
||||
import net.minestom.server.network.packet.PacketReader;
|
||||
import net.minestom.server.network.packet.PacketWriter;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTException;
|
||||
|
||||
public class InventoryData extends DataType<Inventory> {
|
||||
|
||||
|
@ -35,8 +35,7 @@ public class DamageType {
|
||||
}
|
||||
|
||||
public RichMessage buildChatMessage(Player killed) {
|
||||
RichMessage richMessage = RichMessage.of(ColoredText.ofFormat("{@death." + identifier + "}"))
|
||||
.append(ColoredText.ofFormat(killed.getUsername()));
|
||||
RichMessage richMessage = RichMessage.of(ColoredText.ofFormat("{@death." + identifier + ","+killed.getUsername()+"}"));
|
||||
return richMessage;
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,8 @@ import net.minestom.server.gamedata.loottables.LootTable;
|
||||
import net.minestom.server.gamedata.loottables.LootTableManager;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
import net.minestom.server.utils.nbt.NbtWriter;
|
||||
import net.minestom.server.utils.time.UpdateOption;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
@ -188,12 +188,14 @@ public abstract class CustomBlock {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows custom block to write block entity data to a given NBT compound
|
||||
* Allows custom block to write block entity data to a given NBT compound.
|
||||
* Used to send block entity data to the client over the network.
|
||||
* Can also be used to save block entity data on disk for compatible chunk savers
|
||||
*
|
||||
* @param position position of the block
|
||||
* @param blockData equivalent to <pre>instance.getBlockData(position)</pre>
|
||||
*/
|
||||
public void writeBlockEntity(BlockPosition position, Data blockData, NbtWriter nbt) {
|
||||
public void writeBlockEntity(BlockPosition position, Data blockData, NBTCompound nbt) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6,13 +6,18 @@ import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
import net.minestom.server.utils.SerializerUtils;
|
||||
import net.minestom.server.utils.Utils;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTException;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTReader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.UUID;
|
||||
|
||||
// TODO delete
|
||||
public class PacketReader {
|
||||
public class PacketReader extends InputStream {
|
||||
|
||||
private ByteBuf buffer;
|
||||
private NBTReader nbtReader = new NBTReader(this, false);
|
||||
|
||||
public PacketReader(ByteBuf buffer) {
|
||||
this.buffer = buffer;
|
||||
@ -106,4 +111,13 @@ public class PacketReader {
|
||||
public ByteBuf getBuffer() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
return readByte();
|
||||
}
|
||||
|
||||
public NBT readTag() throws IOException, NBTException {
|
||||
return nbtReader.read();
|
||||
}
|
||||
}
|
||||
|
@ -7,15 +7,20 @@ import net.minestom.server.utils.BlockPosition;
|
||||
import net.minestom.server.utils.SerializerUtils;
|
||||
import net.minestom.server.utils.Utils;
|
||||
import net.minestom.server.utils.buffer.BufferWrapper;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class PacketWriter {
|
||||
public class PacketWriter extends OutputStream {
|
||||
|
||||
private ByteBuf buffer = Unpooled.buffer();
|
||||
private NBTWriter nbtWriter = new NBTWriter(this, false);
|
||||
|
||||
public void writeBoolean(boolean b) {
|
||||
buffer.writeBoolean(b);
|
||||
@ -128,6 +133,15 @@ public class PacketWriter {
|
||||
Utils.writeItemStack(this, itemStack);
|
||||
}
|
||||
|
||||
public void writeNBT(String name, NBT tag) {
|
||||
try {
|
||||
nbtWriter.writeNamed("", tag);
|
||||
} catch (IOException e) {
|
||||
// should not throw, as nbtWriter points to this PacketWriter
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] toByteArray() {
|
||||
byte[] bytes = new byte[buffer.readableBytes()];
|
||||
int readerIndex = buffer.readerIndex();
|
||||
@ -135,4 +149,8 @@ public class PacketWriter {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) {
|
||||
writeByte((byte) b);
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ import net.minestom.server.entity.GameMode;
|
||||
import net.minestom.server.network.packet.PacketWriter;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import net.minestom.server.utils.nbt.NbtWriter;
|
||||
import net.minestom.server.world.Dimension;
|
||||
import net.minestom.server.world.LevelType;
|
||||
|
||||
import static net.minestom.server.utils.nbt.NBT.*;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTList;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTTypes;
|
||||
|
||||
public class JoinGamePacket implements ServerPacket {
|
||||
|
||||
@ -27,7 +27,6 @@ public class JoinGamePacket implements ServerPacket {
|
||||
|
||||
@Override
|
||||
public void write(PacketWriter writer) {
|
||||
NbtWriter nbtWriter = new NbtWriter(writer);
|
||||
int gameModeId = gameMode.getId();
|
||||
if (gameMode.isHardcore())
|
||||
gameModeId |= 8;
|
||||
@ -40,23 +39,26 @@ public class JoinGamePacket implements ServerPacket {
|
||||
//array of worlds
|
||||
writer.writeVarInt(1);
|
||||
writer.writeSizedString(identifier);
|
||||
nbtWriter.writeCompound("", (writer1) -> {
|
||||
writer1.writeList("dimension", NBT_COMPOUND, 1, () -> {
|
||||
writer1.writeString("name", "test:normal");
|
||||
writer1.writeFloat("ambient_light", 1F);
|
||||
writer1.writeString("infiniburn", "");
|
||||
writer1.writeByte("natural", (byte) 0x01);
|
||||
writer1.writeByte("has_ceiling", (byte) 0x01);
|
||||
writer1.writeByte("has_skylight", (byte) 0x01);
|
||||
writer1.writeByte("shrunk", (byte) 0x00);
|
||||
writer1.writeByte("ultrawarm", (byte) 0x00);
|
||||
writer1.writeByte("has_raids", (byte) 0x00);
|
||||
writer1.writeByte("respawn_anchor_works", (byte) 0x00);
|
||||
writer1.writeByte("bed_works", (byte) 0x01);
|
||||
writer1.writeByte("piglin_safe", (byte) 0x01);
|
||||
writer1.writeInt("logical_height", 255);
|
||||
});
|
||||
});
|
||||
// TODO: modifiable
|
||||
NBTCompound dimension = new NBTCompound()
|
||||
.setString("name", "test:normal")
|
||||
.setFloat("ambient_light", 1F)
|
||||
.setString("infiniburn", "")
|
||||
.setByte("natural", (byte) 0x01)
|
||||
.setByte("has_ceiling", (byte) 0x01)
|
||||
.setByte("has_skylight", (byte) 0x01)
|
||||
.setByte("shrunk", (byte) 0x00)
|
||||
.setByte("ultrawarm", (byte) 0x00)
|
||||
.setByte("has_raids", (byte) 0x00)
|
||||
.setByte("respawn_anchor_works", (byte) 0x00)
|
||||
.setByte("bed_works", (byte) 0x01)
|
||||
.setByte("piglin_safe", (byte) 0x01)
|
||||
.setInt("logical_height", 255)
|
||||
;
|
||||
NBTList<NBTCompound> dimensionList = new NBTList<>(NBTTypes.TAG_Compound);
|
||||
dimensionList.add(dimension);
|
||||
writer.writeNBT("", new NBTCompound().set("dimension", dimensionList));
|
||||
|
||||
|
||||
//writer.writeInt(dimension.getId());
|
||||
writer.writeSizedString("test:normal");
|
||||
|
@ -15,7 +15,7 @@ import net.minestom.server.utils.Utils;
|
||||
import net.minestom.server.utils.buffer.BufferUtils;
|
||||
import net.minestom.server.utils.buffer.BufferWrapper;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
import net.minestom.server.utils.nbt.NbtWriter;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@ -44,8 +44,6 @@ public class ChunkDataPacket implements ServerPacket {
|
||||
|
||||
@Override
|
||||
public void write(PacketWriter writer) {
|
||||
NbtWriter nbtWriter = new NbtWriter(writer);
|
||||
|
||||
writer.writeInt(chunkX);
|
||||
writer.writeInt(chunkZ);
|
||||
writer.writeBoolean(fullChunk);
|
||||
@ -81,10 +79,11 @@ public class ChunkDataPacket implements ServerPacket {
|
||||
}
|
||||
|
||||
{
|
||||
nbtWriter.writeCompound("", compound -> {
|
||||
compound.writeLongArray("MOTION_BLOCKING", Utils.encodeBlocks(motionBlocking, 9));
|
||||
compound.writeLongArray("WORLD_SURFACE", Utils.encodeBlocks(worldSurface, 9));
|
||||
});
|
||||
writer.writeNBT("",
|
||||
new NBTCompound()
|
||||
.setLongArray("MOTION_BLOCKING", Utils.encodeBlocks(motionBlocking, 9))
|
||||
.setLongArray("WORLD_SURFACE", Utils.encodeBlocks(worldSurface, 9))
|
||||
);
|
||||
}
|
||||
|
||||
// Biome data
|
||||
@ -104,18 +103,18 @@ public class ChunkDataPacket implements ServerPacket {
|
||||
for (int index : blockEntities) {
|
||||
final BlockPosition blockPosition = ChunkUtils.getBlockPosition(index, chunkX, chunkZ);
|
||||
|
||||
nbtWriter.writeCompound("", compound -> {
|
||||
compound.writeDouble("x", blockPosition.getX());
|
||||
compound.writeDouble("y", blockPosition.getY());
|
||||
compound.writeDouble("z", blockPosition.getZ());
|
||||
NBTCompound nbt = new NBTCompound()
|
||||
.setDouble("x", blockPosition.getX())
|
||||
.setDouble("y", blockPosition.getY())
|
||||
.setDouble("z", blockPosition.getZ());
|
||||
|
||||
final short customBlockId = customBlocksId[index];
|
||||
final CustomBlock customBlock = BLOCK_MANAGER.getCustomBlock(customBlockId);
|
||||
if (customBlock != null) {
|
||||
Data data = blocksData.get(index);
|
||||
customBlock.writeBlockEntity(blockPosition, data, compound);
|
||||
}
|
||||
});
|
||||
final short customBlockId = customBlocksId[index];
|
||||
final CustomBlock customBlock = BLOCK_MANAGER.getCustomBlock(customBlockId);
|
||||
if (customBlock != null) {
|
||||
Data data = blocksData.get(index);
|
||||
customBlock.writeBlockEntity(blockPosition, data, nbt);
|
||||
}
|
||||
writer.writeNBT("", nbt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,23 +1,30 @@
|
||||
package net.minestom.server.utils;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minestom.server.attribute.Attribute;
|
||||
import net.minestom.server.attribute.AttributeOperation;
|
||||
import net.minestom.server.chat.ColoredText;
|
||||
import net.minestom.server.instance.Chunk;
|
||||
import net.minestom.server.item.Enchantment;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.attribute.AttributeSlot;
|
||||
import net.minestom.server.item.attribute.ItemAttribute;
|
||||
import net.minestom.server.network.packet.PacketReader;
|
||||
import net.minestom.server.network.packet.PacketWriter;
|
||||
import net.minestom.server.potion.PotionType;
|
||||
import net.minestom.server.registry.Registries;
|
||||
import net.minestom.server.utils.buffer.BufferWrapper;
|
||||
import net.minestom.server.utils.item.NbtReaderUtils;
|
||||
import net.minestom.server.utils.nbt.NBT;
|
||||
import net.minestom.server.utils.nbt.NbtWriter;
|
||||
import org.jglrxavpok.hephaistos.nbt.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class Utils {
|
||||
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(Utils.class);
|
||||
|
||||
public static int getVarIntSize(int input) {
|
||||
return (input & 0xFFFFFF80) == 0
|
||||
? 1 : (input & 0xFFFFC000) == 0
|
||||
@ -110,18 +117,18 @@ public class Utils {
|
||||
70409299, 70409299, 0, 69273666, 69273666, 0, 68174084, 68174084, 0, Integer.MIN_VALUE,
|
||||
0, 5};
|
||||
|
||||
private static void writeEnchant(NbtWriter writer, String listName, Map<Enchantment, Short> enchantmentMap) {
|
||||
writer.writeList(listName, NBT.NBT_COMPOUND, enchantmentMap.size(), () -> {
|
||||
for (Map.Entry<Enchantment, Short> entry : enchantmentMap.entrySet()) {
|
||||
Enchantment enchantment = entry.getKey();
|
||||
short level = entry.getValue();
|
||||
private static void writeEnchant(NBTCompound nbt, String listName, Map<Enchantment, Short> enchantmentMap) {
|
||||
NBTList<NBTCompound> enchantList = new NBTList<>(NBTTypes.TAG_Compound);
|
||||
for (Map.Entry<Enchantment, Short> entry : enchantmentMap.entrySet()) {
|
||||
Enchantment enchantment = entry.getKey();
|
||||
short level = entry.getValue();
|
||||
|
||||
writer.writeShort("lvl", level);
|
||||
|
||||
writer.writeString("id", "minecraft:" + enchantment.name().toLowerCase());
|
||||
|
||||
}
|
||||
});
|
||||
enchantList.add(new NBTCompound()
|
||||
.setShort("lvl", level)
|
||||
.setString("id", "minecraft:" + enchantment.name().toLowerCase())
|
||||
);
|
||||
}
|
||||
nbt.set(listName, enchantList);
|
||||
}
|
||||
|
||||
public static ItemStack readItemStack(PacketReader reader) {
|
||||
@ -141,18 +148,91 @@ public class Utils {
|
||||
|
||||
ItemStack item = new ItemStack((short) id, count);
|
||||
|
||||
byte nbt = reader.readByte(); // Should be compound start (0x0A) or 0 if there isn't NBT data
|
||||
try {
|
||||
NBT itemNBT = reader.readTag();
|
||||
if(itemNBT instanceof NBTCompound) { // can also be a TAG_End if no data
|
||||
NBTCompound nbt = (NBTCompound) itemNBT;
|
||||
if(nbt.containsKey("Damage")) item.setDamage(nbt.getShort("Damage"));
|
||||
if(nbt.containsKey("Unbreakable")) item.setUnbreakable(nbt.getInt("Unbreakable") == 1);
|
||||
if(nbt.containsKey("HideFlags")) item.setHideFlag(nbt.getInt("HideFlags"));
|
||||
if(nbt.containsKey("Potion")) item.addPotionType(Registries.getPotionType(nbt.getString("Potion")));
|
||||
if(nbt.containsKey("display")) {
|
||||
NBTCompound display = nbt.getCompound("display");
|
||||
if(display.containsKey("Name")) item.setDisplayName(ColoredText.of(display.getString("Name")));
|
||||
if(display.containsKey("Lore")) {
|
||||
NBTList<NBTString> loreList = display.getList("Lore");
|
||||
ArrayList<ColoredText> lore = new ArrayList<>();
|
||||
for(NBTString s : loreList) {
|
||||
lore.add(ColoredText.of(s.getValue()));
|
||||
}
|
||||
item.setLore(lore);
|
||||
}
|
||||
}
|
||||
|
||||
if (nbt == 0x00) {
|
||||
return item;
|
||||
} else if (nbt == 0x0A) {
|
||||
reader.readShort(); // Ignored, should be empty (main compound name)
|
||||
NbtReaderUtils.readItemStackNBT(reader, item);
|
||||
if(nbt.containsKey("Enchantments")) {
|
||||
loadEnchantments(nbt.getList("Enchantments"), item::setEnchantment);
|
||||
}
|
||||
if(nbt.containsKey("StoredEnchantments")) {
|
||||
loadEnchantments(nbt.getList("StoredEnchantments"), item::setStoredEnchantment);
|
||||
}
|
||||
if(nbt.containsKey("AttributeModifiers")) {
|
||||
NBTList<NBTCompound> attributes = nbt.getList("AttributeModifiers");
|
||||
for (NBTCompound attributeNBT : attributes) {
|
||||
// TODO: 1.16 changed how UUIDs are stored, is this part affected?
|
||||
long uuidMost = attributeNBT.getLong("UUIDMost");
|
||||
long uuidLeast = attributeNBT.getLong("UUIDLeast");
|
||||
UUID uuid = new UUID(uuidMost, uuidLeast);
|
||||
double value = attributeNBT.getDouble("Amount");
|
||||
String slot = attributeNBT.getString("Slot");
|
||||
String attributeName = attributeNBT.getString("AttributeName");
|
||||
int operation = attributeNBT.getInt("Operation");
|
||||
String name = attributeNBT.getString("Name");
|
||||
|
||||
final Attribute attribute = Attribute.fromKey(attributeName);
|
||||
// Wrong attribute name, stop here
|
||||
if (attribute == null)
|
||||
break;
|
||||
final AttributeOperation attributeOperation = AttributeOperation.byId(operation);
|
||||
// Wrong attribute operation, stop here
|
||||
if (attributeOperation == null)
|
||||
break;
|
||||
final AttributeSlot attributeSlot = AttributeSlot.valueOf(slot.toUpperCase());
|
||||
// Wrong attribute slot, stop here
|
||||
if (attributeSlot == null)
|
||||
break;
|
||||
|
||||
// Add attribute
|
||||
final ItemAttribute itemAttribute =
|
||||
new ItemAttribute(uuid, name, attribute, attributeOperation, value, attributeSlot);
|
||||
item.addAttribute(itemAttribute);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException | NBTException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface EnchantmentSetter {
|
||||
void applyEnchantment(Enchantment name, short level);
|
||||
}
|
||||
|
||||
private static void loadEnchantments(NBTList<NBTCompound> enchantments, EnchantmentSetter setter) {
|
||||
for(NBTCompound enchantment : enchantments) {
|
||||
short level = enchantment.getShort("lvl");
|
||||
String id = enchantment.getString("id");
|
||||
Enchantment enchant = Registries.getEnchantment(id);
|
||||
if(enchant != null) {
|
||||
setter.applyEnchantment(enchant, level);
|
||||
} else {
|
||||
LOGGER.warn("Unknown enchantment type: "+id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeBlocks(BufferWrapper buffer, short[] blocksId, int bitsPerEntry) {
|
||||
short count = 0;
|
||||
for (short id : blocksId)
|
||||
@ -178,28 +258,6 @@ public class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
/*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;
|
||||
}*/
|
||||
|
||||
public static void writeItemStack(PacketWriter packet, ItemStack itemStack) {
|
||||
if (itemStack == null || itemStack.isAir()) {
|
||||
packet.writeBoolean(false);
|
||||
@ -209,126 +267,116 @@ public class Utils {
|
||||
packet.writeByte(itemStack.getAmount());
|
||||
|
||||
if (!itemStack.hasNbtTag()) {
|
||||
packet.writeByte((byte) 0x00); // No nbt
|
||||
packet.writeByte((byte) NBTTypes.TAG_End); // No nbt
|
||||
return;
|
||||
}
|
||||
|
||||
NbtWriter mainWriter = new NbtWriter(packet);
|
||||
NBTCompound itemNBT = new NBTCompound();
|
||||
|
||||
mainWriter.writeCompound("", writer -> {
|
||||
// Unbreakable
|
||||
if (itemStack.isUnbreakable()) {
|
||||
writer.writeInt("Unbreakable", 1);
|
||||
// Unbreakable
|
||||
if (itemStack.isUnbreakable()) {
|
||||
itemNBT.setInt("Unbreakable", 1);
|
||||
}
|
||||
|
||||
// Start damage
|
||||
{
|
||||
itemNBT.setShort("Damage", itemStack.getDamage());
|
||||
}
|
||||
// End damage
|
||||
|
||||
// Display
|
||||
boolean hasDisplayName = itemStack.hasDisplayName();
|
||||
boolean hasLore = itemStack.hasLore();
|
||||
|
||||
if (hasDisplayName || hasLore) {
|
||||
NBTCompound displayNBT = new NBTCompound();
|
||||
if (hasDisplayName) {
|
||||
final String name = itemStack.getDisplayName().toString();
|
||||
displayNBT.setString("Name", name);
|
||||
}
|
||||
|
||||
// Start damage
|
||||
{
|
||||
writer.writeShort("Damage", itemStack.getDamage());
|
||||
}
|
||||
// End damage
|
||||
if (hasLore) {
|
||||
final ArrayList<ColoredText> lore = itemStack.getLore();
|
||||
|
||||
// Display
|
||||
boolean hasDisplayName = itemStack.hasDisplayName();
|
||||
boolean hasLore = itemStack.hasLore();
|
||||
|
||||
if (hasDisplayName || hasLore) {
|
||||
writer.writeCompound("display", displayWriter -> {
|
||||
if (hasDisplayName) {
|
||||
final String name = itemStack.getDisplayName().toString();
|
||||
displayWriter.writeString("Name", name);
|
||||
}
|
||||
|
||||
if (hasLore) {
|
||||
final ArrayList<ColoredText> lore = itemStack.getLore();
|
||||
|
||||
displayWriter.writeList("Lore", NBT.NBT_STRING, lore.size(), () -> {
|
||||
for (ColoredText line : lore) {
|
||||
packet.writeShortSizedString(line.toString());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
// End display
|
||||
|
||||
// Start enchantment
|
||||
{
|
||||
Map<Enchantment, Short> enchantmentMap = itemStack.getEnchantmentMap();
|
||||
if (!enchantmentMap.isEmpty()) {
|
||||
writeEnchant(writer, "Enchantments", enchantmentMap);
|
||||
final NBTList<NBTString> loreNBT = new NBTList<>(NBTTypes.TAG_String);
|
||||
for (ColoredText line : lore) {
|
||||
loreNBT.add(new NBTString(line.toString()));
|
||||
}
|
||||
displayNBT.set("Lore", loreNBT);
|
||||
}
|
||||
|
||||
Map<Enchantment, Short> storedEnchantmentMap = itemStack.getStoredEnchantmentMap();
|
||||
if (!storedEnchantmentMap.isEmpty()) {
|
||||
writeEnchant(writer, "StoredEnchantments", storedEnchantmentMap);
|
||||
itemNBT.set("display", displayNBT);
|
||||
}
|
||||
// End display
|
||||
|
||||
// Start enchantment
|
||||
{
|
||||
Map<Enchantment, Short> enchantmentMap = itemStack.getEnchantmentMap();
|
||||
if (!enchantmentMap.isEmpty()) {
|
||||
writeEnchant(itemNBT, "Enchantments", enchantmentMap);
|
||||
}
|
||||
|
||||
Map<Enchantment, Short> storedEnchantmentMap = itemStack.getStoredEnchantmentMap();
|
||||
if (!storedEnchantmentMap.isEmpty()) {
|
||||
writeEnchant(itemNBT, "StoredEnchantments", storedEnchantmentMap);
|
||||
}
|
||||
}
|
||||
// End enchantment
|
||||
|
||||
// Start attribute
|
||||
{
|
||||
List<ItemAttribute> itemAttributes = itemStack.getAttributes();
|
||||
if (!itemAttributes.isEmpty()) {
|
||||
NBTList<NBTCompound> attributesNBT = new NBTList<>(NBTTypes.TAG_Compound);
|
||||
|
||||
for (ItemAttribute itemAttribute : itemAttributes) {
|
||||
UUID uuid = itemAttribute.getUuid();
|
||||
|
||||
attributesNBT.add(
|
||||
new NBTCompound()
|
||||
.setLong("UUIDMost", uuid.getMostSignificantBits())
|
||||
.setLong("UUIDLeast", uuid.getLeastSignificantBits())
|
||||
.setDouble("Amount", itemAttribute.getValue())
|
||||
.setString("Slot", itemAttribute.getSlot().name().toLowerCase())
|
||||
.setString("itemAttribute", itemAttribute.getAttribute().getKey())
|
||||
.setInt("Operation", itemAttribute.getOperation().getId())
|
||||
.setString("Name", itemAttribute.getInternalName())
|
||||
);
|
||||
}
|
||||
itemNBT.set("AttributeModifiers", attributesNBT);
|
||||
}
|
||||
}
|
||||
// End attribute
|
||||
|
||||
// Start potion
|
||||
{
|
||||
Set<PotionType> potionTypes = itemStack.getPotionTypes();
|
||||
if (!potionTypes.isEmpty()) {
|
||||
for (PotionType potionType : potionTypes) {
|
||||
itemNBT.setString("Potion", potionType.getNamespaceID());
|
||||
}
|
||||
}
|
||||
// End enchantment
|
||||
}
|
||||
// End potion
|
||||
|
||||
// Start attribute
|
||||
{
|
||||
List<ItemAttribute> itemAttributes = itemStack.getAttributes();
|
||||
if (!itemAttributes.isEmpty()) {
|
||||
packet.writeByte((byte) 0x09); // Type id (list)
|
||||
packet.writeShortSizedString("AttributeModifiers");
|
||||
|
||||
packet.writeByte((byte) 0x0A); // Compound
|
||||
packet.writeInt(itemAttributes.size());
|
||||
|
||||
for (ItemAttribute itemAttribute : itemAttributes) {
|
||||
UUID uuid = itemAttribute.getUuid();
|
||||
|
||||
writer.writeLong("UUIDMost", uuid.getMostSignificantBits());
|
||||
|
||||
writer.writeLong("UUIDLeast", uuid.getLeastSignificantBits());
|
||||
|
||||
writer.writeDouble("Amount", itemAttribute.getValue());
|
||||
|
||||
writer.writeString("Slot", itemAttribute.getSlot().name().toLowerCase());
|
||||
|
||||
writer.writeString("itemAttribute", itemAttribute.getAttribute().getKey());
|
||||
|
||||
writer.writeInt("Operation", itemAttribute.getOperation().getId());
|
||||
|
||||
writer.writeString("Name", itemAttribute.getInternalName());
|
||||
}
|
||||
packet.writeByte((byte) 0x00); // End compound
|
||||
}
|
||||
// Start hide flags
|
||||
{
|
||||
int hideFlag = itemStack.getHideFlag();
|
||||
if (hideFlag != 0) {
|
||||
itemNBT.setInt("HideFlags", hideFlag);
|
||||
}
|
||||
// End attribute
|
||||
}
|
||||
// End hide flags
|
||||
|
||||
// Start potion
|
||||
{
|
||||
Set<PotionType> potionTypes = itemStack.getPotionTypes();
|
||||
if (!potionTypes.isEmpty()) {
|
||||
for (PotionType potionType : potionTypes) {
|
||||
packet.writeByte((byte) 0x08); // type id (string)
|
||||
packet.writeShortSizedString("Potion");
|
||||
packet.writeShortSizedString("minecraft:" + potionType.name().toLowerCase());
|
||||
}
|
||||
}
|
||||
// Start custom model data
|
||||
{
|
||||
int customModelData = itemStack.getCustomModelData();
|
||||
if (customModelData != 0) {
|
||||
itemNBT.setInt("CustomModelData", customModelData);
|
||||
}
|
||||
// End potion
|
||||
|
||||
// Start hide flags
|
||||
{
|
||||
int hideFlag = itemStack.getHideFlag();
|
||||
if (hideFlag != 0) {
|
||||
writer.writeInt("HideFlags", hideFlag);
|
||||
}
|
||||
}
|
||||
// End hide flags
|
||||
|
||||
// Start custom model data
|
||||
{
|
||||
int customModelData = itemStack.getCustomModelData();
|
||||
if (customModelData != 0) {
|
||||
writer.writeInt("CustomModelData", customModelData);
|
||||
}
|
||||
}
|
||||
// End custom model data
|
||||
});
|
||||
}
|
||||
// End custom model data
|
||||
packet.writeNBT("", itemNBT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,246 +0,0 @@
|
||||
package net.minestom.server.utils.item;
|
||||
|
||||
import net.minestom.server.attribute.Attribute;
|
||||
import net.minestom.server.attribute.AttributeOperation;
|
||||
import net.minestom.server.chat.ChatParser;
|
||||
import net.minestom.server.chat.ColoredText;
|
||||
import net.minestom.server.item.Enchantment;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.attribute.AttributeSlot;
|
||||
import net.minestom.server.item.attribute.ItemAttribute;
|
||||
import net.minestom.server.network.packet.PacketReader;
|
||||
import net.minestom.server.potion.PotionType;
|
||||
import net.minestom.server.registry.Registries;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
public class NbtReaderUtils {
|
||||
|
||||
public static void readItemStackNBT(PacketReader reader, ItemStack item) {
|
||||
|
||||
byte typeId = reader.readByte();
|
||||
|
||||
//System.out.println("DEBUG TYPE: " + typeId);
|
||||
switch (typeId) {
|
||||
case 0x00: // TAG_End
|
||||
// End of item NBT
|
||||
return;
|
||||
case 0x01: // TAG_Byte
|
||||
|
||||
break;
|
||||
case 0x02: // TAG_Short
|
||||
String shortName = reader.readShortSizedString();
|
||||
|
||||
// Damage NBT
|
||||
if (shortName.equals("Damage")) {
|
||||
short damage = reader.readShort();
|
||||
item.setDamage(damage);
|
||||
readItemStackNBT(reader, item);
|
||||
}
|
||||
break;
|
||||
case 0x03: // TAG_Int
|
||||
String intName = reader.readShortSizedString();
|
||||
|
||||
// Damage
|
||||
if (intName.equals("Damage")) {
|
||||
int damage = reader.readInteger();
|
||||
//item.setDamage(damage);
|
||||
// TODO short vs int damage
|
||||
readItemStackNBT(reader, item);
|
||||
}
|
||||
|
||||
// Unbreakable
|
||||
if (intName.equals("Unbreakable")) {
|
||||
int value = reader.readInteger();
|
||||
item.setUnbreakable(value == 1);
|
||||
readItemStackNBT(reader, item);
|
||||
}
|
||||
|
||||
if (intName.equals("HideFlags")) {
|
||||
int flag = reader.readInteger();
|
||||
item.setHideFlag(flag);
|
||||
readItemStackNBT(reader, item);
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x04: // TAG_Long
|
||||
|
||||
break;
|
||||
case 0x05: // TAG_Float
|
||||
|
||||
break;
|
||||
case 0x06: // TAG_Double
|
||||
|
||||
break;
|
||||
case 0x07: // TAG_Byte_Array
|
||||
|
||||
break;
|
||||
case 0x08: // TAG_String
|
||||
String stringName = reader.readShortSizedString();
|
||||
|
||||
if (stringName.equals("Potion")) {
|
||||
String potionId = reader.readShortSizedString();
|
||||
PotionType potionType = Registries.getPotionType(potionId);
|
||||
|
||||
item.addPotionType(potionType);
|
||||
|
||||
readItemStackNBT(reader, item);
|
||||
}
|
||||
break;
|
||||
case 0x09: // TAG_List
|
||||
|
||||
String listName = reader.readShortSizedString();
|
||||
|
||||
final boolean isEnchantment = listName.equals("Enchantments");
|
||||
final boolean isStoredEnchantment = listName.equals("StoredEnchantments");
|
||||
if (isEnchantment || isStoredEnchantment) {
|
||||
reader.readByte(); // Should be a compound (0x0A)
|
||||
int size = reader.readInteger(); // Enchantments count
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
reader.readByte(); // Type id (short)
|
||||
reader.readShortSizedString(); // Constant "lvl"
|
||||
short lvl = reader.readShort();
|
||||
|
||||
reader.readByte(); // Type id (string)
|
||||
reader.readShortSizedString(); // Constant "id"
|
||||
String id = reader.readShortSizedString();
|
||||
|
||||
// Convert id
|
||||
Enchantment enchantment = Registries.getEnchantment(id);
|
||||
|
||||
if (isEnchantment) {
|
||||
item.setEnchantment(enchantment, lvl);
|
||||
} else if (isStoredEnchantment) {
|
||||
item.setStoredEnchantment(enchantment, lvl);
|
||||
}
|
||||
}
|
||||
|
||||
reader.readByte(); // Compound end
|
||||
|
||||
readItemStackNBT(reader, item);
|
||||
|
||||
}
|
||||
|
||||
if (listName.equals("AttributeModifiers")) {
|
||||
reader.readByte(); // Should be a compound (0x0A);
|
||||
int size = reader.readInteger(); // Attributes count
|
||||
for (int i = 0; i < size; i++) {
|
||||
reader.readByte(); // Type id (long)
|
||||
reader.readShortSizedString(); // Constant "UUIDMost"
|
||||
long uuidMost = reader.readLong();
|
||||
|
||||
reader.readByte(); // Type id (long)
|
||||
reader.readShortSizedString(); // Constant "UUIDLeast"
|
||||
long uuidLeast = reader.readLong();
|
||||
|
||||
final UUID uuid = new UUID(uuidMost, uuidLeast);
|
||||
|
||||
reader.readByte(); // Type id (double)
|
||||
reader.readShortSizedString(); // Constant "Amount"
|
||||
final double value = reader.readDouble();
|
||||
|
||||
reader.readByte(); // Type id (string)
|
||||
reader.readShortSizedString(); // Constant "Slot"
|
||||
final String slot = reader.readShortSizedString();
|
||||
|
||||
reader.readByte(); // Type id (string)
|
||||
reader.readShortSizedString(); // Constant "AttributeName"
|
||||
final String attributeName = reader.readShortSizedString();
|
||||
|
||||
reader.readByte(); // Type id (int)
|
||||
reader.readShortSizedString(); // Constant "Operation"
|
||||
final int operation = reader.readInteger();
|
||||
|
||||
reader.readByte(); // Type id (string)
|
||||
reader.readShortSizedString(); // Constant "Name"
|
||||
final String name = reader.readShortSizedString();
|
||||
|
||||
final Attribute attribute = Attribute.fromKey(attributeName);
|
||||
// Wrong attribute name, stop here
|
||||
if (attribute == null)
|
||||
break;
|
||||
final AttributeOperation attributeOperation = AttributeOperation.byId(operation);
|
||||
// Wrong attribute operation, stop here
|
||||
if (attributeOperation == null)
|
||||
break;
|
||||
final AttributeSlot attributeSlot = AttributeSlot.valueOf(slot.toUpperCase());
|
||||
// Wrong attribute slot, stop here
|
||||
if (attributeSlot == null)
|
||||
break;
|
||||
|
||||
// Add attribute
|
||||
final ItemAttribute itemAttribute =
|
||||
new ItemAttribute(uuid, name, attribute, attributeOperation, value, attributeSlot);
|
||||
item.addAttribute(itemAttribute);
|
||||
}
|
||||
|
||||
reader.readByte(); // Compound end
|
||||
|
||||
readItemStackNBT(reader, item);
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x0A: // TAG_Compound
|
||||
|
||||
String compoundName = reader.readShortSizedString();
|
||||
|
||||
// Display Compound
|
||||
if (compoundName.equals("display")) {
|
||||
readItemStackDisplayNBT(reader, item);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void readItemStackDisplayNBT(PacketReader reader, ItemStack item) {
|
||||
byte typeId = reader.readByte();
|
||||
|
||||
switch (typeId) {
|
||||
case 0x00: // TAG_End
|
||||
// End of the display compound
|
||||
readItemStackNBT(reader, item);
|
||||
break;
|
||||
case 0x08: // TAG_String
|
||||
|
||||
String stringName = reader.readShortSizedString();
|
||||
|
||||
if (stringName.equals("Name")) {
|
||||
String jsonDisplayName = reader.readShortSizedString();
|
||||
ColoredText displayName = ChatParser.toColoredText(jsonDisplayName);
|
||||
|
||||
item.setDisplayName(displayName);
|
||||
readItemStackDisplayNBT(reader, item);
|
||||
}
|
||||
break;
|
||||
case 0x09: // TAG_List
|
||||
|
||||
String listName = reader.readShortSizedString();
|
||||
|
||||
if (listName.equals("Lore")) {
|
||||
reader.readByte(); // lore type, should always be 0x08 (TAG_String)
|
||||
|
||||
int size = reader.readInteger();
|
||||
ArrayList<ColoredText> lore = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
String string = reader.readShortSizedString();
|
||||
ColoredText text = ChatParser.toColoredText(string);
|
||||
|
||||
lore.add(text);
|
||||
if (lore.size() == size) {
|
||||
item.setLore(lore);
|
||||
}
|
||||
|
||||
if (i == size - 1) { // Last iteration
|
||||
readItemStackDisplayNBT(reader, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package net.minestom.server.utils.nbt;
|
||||
|
||||
public class NBT {
|
||||
|
||||
public static final byte NBT_BYTE = 0x01;
|
||||
public static final byte NBT_SHORT = 0x02;
|
||||
public static final byte NBT_INT = 0x03;
|
||||
public static final byte NBT_LONG = 0x04;
|
||||
public static final byte NBT_FLOAT = 0x05;
|
||||
public static final byte NBT_DOUBLE = 0x06;
|
||||
public static final byte NBT_BYTE_ARRAY = 0x07;
|
||||
public static final byte NBT_STRING = 0x08;
|
||||
public static final byte NBT_LIST = 0x09;
|
||||
public static final byte NBT_COMPOUND = 0x0A;
|
||||
public static final byte NBT_INT_ARRAY = 0x0B;
|
||||
public static final byte NBT_LONG_ARRAY = 0x0C;
|
||||
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package net.minestom.server.utils.nbt;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface NbtConsumer {
|
||||
void accept(NbtWriter writer);
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
package net.minestom.server.utils.nbt;
|
||||
|
||||
import net.minestom.server.network.packet.PacketWriter;
|
||||
import net.minestom.server.utils.MathUtils;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
|
||||
import static net.minestom.server.utils.nbt.NBT.*;
|
||||
|
||||
public class NbtWriter {
|
||||
|
||||
private PacketWriter packet;
|
||||
|
||||
public NbtWriter(PacketWriter packet) {
|
||||
this.packet = packet;
|
||||
}
|
||||
|
||||
public void writeByte(String name, byte value) {
|
||||
writeHeader(NBT_BYTE, name);
|
||||
packet.writeByte(value);
|
||||
}
|
||||
|
||||
public void writeShort(String name, short value) {
|
||||
writeHeader(NBT_SHORT, name);
|
||||
packet.writeShort(value);
|
||||
}
|
||||
|
||||
public void writeInt(String name, int value) {
|
||||
writeHeader(NBT_INT, name);
|
||||
packet.writeInt(value);
|
||||
}
|
||||
|
||||
public void writeLong(String name, long value) {
|
||||
writeHeader(NBT_LONG, name);
|
||||
packet.writeLong(value);
|
||||
}
|
||||
|
||||
public void writeFloat(String name, float value) {
|
||||
writeHeader(NBT_FLOAT, name);
|
||||
packet.writeFloat(value);
|
||||
}
|
||||
|
||||
public void writeDouble(String name, double value) {
|
||||
writeHeader(NBT_DOUBLE, name);
|
||||
packet.writeDouble(value);
|
||||
}
|
||||
|
||||
public void writeByteArray(String name, byte[] value) {
|
||||
writeHeader(NBT_BYTE_ARRAY, name);
|
||||
packet.writeInt(value.length);
|
||||
for (byte val : value) {
|
||||
packet.writeByte(val);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeString(String name, String value) {
|
||||
writeHeader(NBT_STRING, name);
|
||||
packet.writeShortSizedString(value);
|
||||
}
|
||||
|
||||
public void writeList(String name, byte type, int size, Runnable callback) {
|
||||
writeHeader(NBT_LIST, name);
|
||||
packet.writeByte(type);
|
||||
packet.writeInt(size);
|
||||
callback.run();
|
||||
if (type == NBT_COMPOUND)
|
||||
packet.writeByte((byte) 0x00); // End compount
|
||||
}
|
||||
|
||||
public void writeCompound(String name, NbtConsumer consumer) {
|
||||
writeHeader(NBT_COMPOUND, name);
|
||||
consumer.accept(this);
|
||||
packet.writeByte((byte) 0x00); // End compound
|
||||
}
|
||||
|
||||
public void writeIntArray(String name, int[] value) {
|
||||
writeHeader(NBT_INT_ARRAY, name);
|
||||
packet.writeInt(value.length);
|
||||
for (int val : value) {
|
||||
packet.writeInt(val);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeLongArray(String name, long[] value) {
|
||||
writeHeader(NBT_LONG_ARRAY, name);
|
||||
packet.writeInt(value.length);
|
||||
for (long val : value) {
|
||||
packet.writeLong(val);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeHeader(byte type, String name) {
|
||||
Check.argCondition(!MathUtils.isBetween(type, NBT_BYTE, NBT_LONG_ARRAY),
|
||||
"The NbtTag type " + type + " is not valid");
|
||||
Check.notNull(name, "The NbtTag name cannot be null");
|
||||
packet.writeByte(type);
|
||||
packet.writeShortSizedString(name);
|
||||
}
|
||||
|
||||
public PacketWriter getPacketWriter() {
|
||||
return packet;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user