mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-31 21:48:08 +01:00
Remove old NBT code, use Hephaistos
This commit is contained in:
parent
c061e2a71f
commit
4f4d48df92
@ -1,6 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'java-library'
|
id 'java-library'
|
||||||
id 'net.ltgt.apt' version '0.10'
|
id 'net.ltgt.apt' version '0.10'
|
||||||
|
id 'org.jetbrains.kotlin.jvm' version '1.3.72'
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
@ -71,4 +72,6 @@ dependencies {
|
|||||||
// Pathfinding
|
// Pathfinding
|
||||||
implementation 'com.github.MadMartian:hydrazine-path-finding:1.1.0'
|
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.command.CommandManager;
|
||||||
import net.minestom.server.data.DataManager;
|
import net.minestom.server.data.DataManager;
|
||||||
import net.minestom.server.entity.EntityManager;
|
import net.minestom.server.entity.EntityManager;
|
||||||
|
import net.minestom.server.entity.EntityType;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.extras.mojangAuth.MojangCrypt;
|
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.loottables.LootTableManager;
|
||||||
import net.minestom.server.gamedata.tags.TagManager;
|
import net.minestom.server.gamedata.tags.TagManager;
|
||||||
|
import net.minestom.server.instance.Biome;
|
||||||
import net.minestom.server.instance.InstanceManager;
|
import net.minestom.server.instance.InstanceManager;
|
||||||
|
import net.minestom.server.instance.block.Block;
|
||||||
import net.minestom.server.instance.block.BlockManager;
|
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.listener.manager.PacketListenerManager;
|
||||||
import net.minestom.server.network.ConnectionManager;
|
import net.minestom.server.network.ConnectionManager;
|
||||||
import net.minestom.server.network.PacketProcessor;
|
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.netty.NettyServer;
|
||||||
import net.minestom.server.network.packet.server.play.PluginMessagePacket;
|
import net.minestom.server.network.packet.server.play.PluginMessagePacket;
|
||||||
import net.minestom.server.network.packet.server.play.ServerDifficultyPacket;
|
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.ping.ResponseDataConsumer;
|
||||||
|
import net.minestom.server.potion.PotionType;
|
||||||
import net.minestom.server.recipe.RecipeManager;
|
import net.minestom.server.recipe.RecipeManager;
|
||||||
import net.minestom.server.registry.ResourceGatherer;
|
import net.minestom.server.registry.ResourceGatherer;
|
||||||
import net.minestom.server.scoreboard.TeamManager;
|
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.StorageFolder;
|
||||||
import net.minestom.server.storage.StorageManager;
|
import net.minestom.server.storage.StorageManager;
|
||||||
import net.minestom.server.timer.SchedulerManager;
|
import net.minestom.server.timer.SchedulerManager;
|
||||||
@ -115,6 +125,21 @@ public class MinecraftServer {
|
|||||||
private static MinecraftSessionService sessionService = authService.createMinecraftSessionService();
|
private static MinecraftSessionService sessionService = authService.createMinecraftSessionService();
|
||||||
|
|
||||||
public static MinecraftServer init() {
|
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();
|
connectionManager = new ConnectionManager();
|
||||||
packetProcessor = new PacketProcessor();
|
packetProcessor = new PacketProcessor();
|
||||||
packetListenerManager = new PacketListenerManager();
|
packetListenerManager = new PacketListenerManager();
|
||||||
|
@ -5,6 +5,7 @@ import net.minestom.server.inventory.Inventory;
|
|||||||
import net.minestom.server.inventory.InventoryType;
|
import net.minestom.server.inventory.InventoryType;
|
||||||
import net.minestom.server.network.packet.PacketReader;
|
import net.minestom.server.network.packet.PacketReader;
|
||||||
import net.minestom.server.network.packet.PacketWriter;
|
import net.minestom.server.network.packet.PacketWriter;
|
||||||
|
import org.jglrxavpok.hephaistos.nbt.NBTException;
|
||||||
|
|
||||||
public class InventoryData extends DataType<Inventory> {
|
public class InventoryData extends DataType<Inventory> {
|
||||||
|
|
||||||
|
@ -35,8 +35,7 @@ public class DamageType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public RichMessage buildChatMessage(Player killed) {
|
public RichMessage buildChatMessage(Player killed) {
|
||||||
RichMessage richMessage = RichMessage.of(ColoredText.ofFormat("{@death." + identifier + "}"))
|
RichMessage richMessage = RichMessage.of(ColoredText.ofFormat("{@death." + identifier + ","+killed.getUsername()+"}"));
|
||||||
.append(ColoredText.ofFormat(killed.getUsername()));
|
|
||||||
return richMessage;
|
return richMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@ import net.minestom.server.gamedata.loottables.LootTable;
|
|||||||
import net.minestom.server.gamedata.loottables.LootTableManager;
|
import net.minestom.server.gamedata.loottables.LootTableManager;
|
||||||
import net.minestom.server.instance.Instance;
|
import net.minestom.server.instance.Instance;
|
||||||
import net.minestom.server.utils.BlockPosition;
|
import net.minestom.server.utils.BlockPosition;
|
||||||
import net.minestom.server.utils.nbt.NbtWriter;
|
|
||||||
import net.minestom.server.utils.time.UpdateOption;
|
import net.minestom.server.utils.time.UpdateOption;
|
||||||
|
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* 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 position position of the block
|
||||||
* @param blockData equivalent to <pre>instance.getBlockData(position)</pre>
|
* @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.BlockPosition;
|
||||||
import net.minestom.server.utils.SerializerUtils;
|
import net.minestom.server.utils.SerializerUtils;
|
||||||
import net.minestom.server.utils.Utils;
|
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;
|
import java.util.UUID;
|
||||||
|
|
||||||
// TODO delete
|
public class PacketReader extends InputStream {
|
||||||
public class PacketReader {
|
|
||||||
|
|
||||||
private ByteBuf buffer;
|
private ByteBuf buffer;
|
||||||
|
private NBTReader nbtReader = new NBTReader(this, false);
|
||||||
|
|
||||||
public PacketReader(ByteBuf buffer) {
|
public PacketReader(ByteBuf buffer) {
|
||||||
this.buffer = buffer;
|
this.buffer = buffer;
|
||||||
@ -106,4 +111,13 @@ public class PacketReader {
|
|||||||
public ByteBuf getBuffer() {
|
public ByteBuf getBuffer() {
|
||||||
return buffer;
|
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.SerializerUtils;
|
||||||
import net.minestom.server.utils.Utils;
|
import net.minestom.server.utils.Utils;
|
||||||
import net.minestom.server.utils.buffer.BufferWrapper;
|
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.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class PacketWriter {
|
public class PacketWriter extends OutputStream {
|
||||||
|
|
||||||
private ByteBuf buffer = Unpooled.buffer();
|
private ByteBuf buffer = Unpooled.buffer();
|
||||||
|
private NBTWriter nbtWriter = new NBTWriter(this, false);
|
||||||
|
|
||||||
public void writeBoolean(boolean b) {
|
public void writeBoolean(boolean b) {
|
||||||
buffer.writeBoolean(b);
|
buffer.writeBoolean(b);
|
||||||
@ -128,6 +133,15 @@ public class PacketWriter {
|
|||||||
Utils.writeItemStack(this, itemStack);
|
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() {
|
public byte[] toByteArray() {
|
||||||
byte[] bytes = new byte[buffer.readableBytes()];
|
byte[] bytes = new byte[buffer.readableBytes()];
|
||||||
int readerIndex = buffer.readerIndex();
|
int readerIndex = buffer.readerIndex();
|
||||||
@ -135,4 +149,8 @@ public class PacketWriter {
|
|||||||
return bytes;
|
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.PacketWriter;
|
||||||
import net.minestom.server.network.packet.server.ServerPacket;
|
import net.minestom.server.network.packet.server.ServerPacket;
|
||||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
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.Dimension;
|
||||||
import net.minestom.server.world.LevelType;
|
import net.minestom.server.world.LevelType;
|
||||||
|
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||||
import static net.minestom.server.utils.nbt.NBT.*;
|
import org.jglrxavpok.hephaistos.nbt.NBTList;
|
||||||
|
import org.jglrxavpok.hephaistos.nbt.NBTTypes;
|
||||||
|
|
||||||
public class JoinGamePacket implements ServerPacket {
|
public class JoinGamePacket implements ServerPacket {
|
||||||
|
|
||||||
@ -27,7 +27,6 @@ public class JoinGamePacket implements ServerPacket {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(PacketWriter writer) {
|
public void write(PacketWriter writer) {
|
||||||
NbtWriter nbtWriter = new NbtWriter(writer);
|
|
||||||
int gameModeId = gameMode.getId();
|
int gameModeId = gameMode.getId();
|
||||||
if (gameMode.isHardcore())
|
if (gameMode.isHardcore())
|
||||||
gameModeId |= 8;
|
gameModeId |= 8;
|
||||||
@ -40,23 +39,26 @@ public class JoinGamePacket implements ServerPacket {
|
|||||||
//array of worlds
|
//array of worlds
|
||||||
writer.writeVarInt(1);
|
writer.writeVarInt(1);
|
||||||
writer.writeSizedString(identifier);
|
writer.writeSizedString(identifier);
|
||||||
nbtWriter.writeCompound("", (writer1) -> {
|
// TODO: modifiable
|
||||||
writer1.writeList("dimension", NBT_COMPOUND, 1, () -> {
|
NBTCompound dimension = new NBTCompound()
|
||||||
writer1.writeString("name", "test:normal");
|
.setString("name", "test:normal")
|
||||||
writer1.writeFloat("ambient_light", 1F);
|
.setFloat("ambient_light", 1F)
|
||||||
writer1.writeString("infiniburn", "");
|
.setString("infiniburn", "")
|
||||||
writer1.writeByte("natural", (byte) 0x01);
|
.setByte("natural", (byte) 0x01)
|
||||||
writer1.writeByte("has_ceiling", (byte) 0x01);
|
.setByte("has_ceiling", (byte) 0x01)
|
||||||
writer1.writeByte("has_skylight", (byte) 0x01);
|
.setByte("has_skylight", (byte) 0x01)
|
||||||
writer1.writeByte("shrunk", (byte) 0x00);
|
.setByte("shrunk", (byte) 0x00)
|
||||||
writer1.writeByte("ultrawarm", (byte) 0x00);
|
.setByte("ultrawarm", (byte) 0x00)
|
||||||
writer1.writeByte("has_raids", (byte) 0x00);
|
.setByte("has_raids", (byte) 0x00)
|
||||||
writer1.writeByte("respawn_anchor_works", (byte) 0x00);
|
.setByte("respawn_anchor_works", (byte) 0x00)
|
||||||
writer1.writeByte("bed_works", (byte) 0x01);
|
.setByte("bed_works", (byte) 0x01)
|
||||||
writer1.writeByte("piglin_safe", (byte) 0x01);
|
.setByte("piglin_safe", (byte) 0x01)
|
||||||
writer1.writeInt("logical_height", 255);
|
.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.writeInt(dimension.getId());
|
||||||
writer.writeSizedString("test:normal");
|
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.BufferUtils;
|
||||||
import net.minestom.server.utils.buffer.BufferWrapper;
|
import net.minestom.server.utils.buffer.BufferWrapper;
|
||||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||||
import net.minestom.server.utils.nbt.NbtWriter;
|
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -44,8 +44,6 @@ public class ChunkDataPacket implements ServerPacket {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(PacketWriter writer) {
|
public void write(PacketWriter writer) {
|
||||||
NbtWriter nbtWriter = new NbtWriter(writer);
|
|
||||||
|
|
||||||
writer.writeInt(chunkX);
|
writer.writeInt(chunkX);
|
||||||
writer.writeInt(chunkZ);
|
writer.writeInt(chunkZ);
|
||||||
writer.writeBoolean(fullChunk);
|
writer.writeBoolean(fullChunk);
|
||||||
@ -81,10 +79,11 @@ public class ChunkDataPacket implements ServerPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
nbtWriter.writeCompound("", compound -> {
|
writer.writeNBT("",
|
||||||
compound.writeLongArray("MOTION_BLOCKING", Utils.encodeBlocks(motionBlocking, 9));
|
new NBTCompound()
|
||||||
compound.writeLongArray("WORLD_SURFACE", Utils.encodeBlocks(worldSurface, 9));
|
.setLongArray("MOTION_BLOCKING", Utils.encodeBlocks(motionBlocking, 9))
|
||||||
});
|
.setLongArray("WORLD_SURFACE", Utils.encodeBlocks(worldSurface, 9))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Biome data
|
// Biome data
|
||||||
@ -104,18 +103,18 @@ public class ChunkDataPacket implements ServerPacket {
|
|||||||
for (int index : blockEntities) {
|
for (int index : blockEntities) {
|
||||||
final BlockPosition blockPosition = ChunkUtils.getBlockPosition(index, chunkX, chunkZ);
|
final BlockPosition blockPosition = ChunkUtils.getBlockPosition(index, chunkX, chunkZ);
|
||||||
|
|
||||||
nbtWriter.writeCompound("", compound -> {
|
NBTCompound nbt = new NBTCompound()
|
||||||
compound.writeDouble("x", blockPosition.getX());
|
.setDouble("x", blockPosition.getX())
|
||||||
compound.writeDouble("y", blockPosition.getY());
|
.setDouble("y", blockPosition.getY())
|
||||||
compound.writeDouble("z", blockPosition.getZ());
|
.setDouble("z", blockPosition.getZ());
|
||||||
|
|
||||||
final short customBlockId = customBlocksId[index];
|
final short customBlockId = customBlocksId[index];
|
||||||
final CustomBlock customBlock = BLOCK_MANAGER.getCustomBlock(customBlockId);
|
final CustomBlock customBlock = BLOCK_MANAGER.getCustomBlock(customBlockId);
|
||||||
if (customBlock != null) {
|
if (customBlock != null) {
|
||||||
Data data = blocksData.get(index);
|
Data data = blocksData.get(index);
|
||||||
customBlock.writeBlockEntity(blockPosition, data, compound);
|
customBlock.writeBlockEntity(blockPosition, data, nbt);
|
||||||
}
|
}
|
||||||
});
|
writer.writeNBT("", nbt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,23 +1,30 @@
|
|||||||
package net.minestom.server.utils;
|
package net.minestom.server.utils;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
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.chat.ColoredText;
|
||||||
import net.minestom.server.instance.Chunk;
|
import net.minestom.server.instance.Chunk;
|
||||||
import net.minestom.server.item.Enchantment;
|
import net.minestom.server.item.Enchantment;
|
||||||
import net.minestom.server.item.ItemStack;
|
import net.minestom.server.item.ItemStack;
|
||||||
|
import net.minestom.server.item.attribute.AttributeSlot;
|
||||||
import net.minestom.server.item.attribute.ItemAttribute;
|
import net.minestom.server.item.attribute.ItemAttribute;
|
||||||
import net.minestom.server.network.packet.PacketReader;
|
import net.minestom.server.network.packet.PacketReader;
|
||||||
import net.minestom.server.network.packet.PacketWriter;
|
import net.minestom.server.network.packet.PacketWriter;
|
||||||
import net.minestom.server.potion.PotionType;
|
import net.minestom.server.potion.PotionType;
|
||||||
|
import net.minestom.server.registry.Registries;
|
||||||
import net.minestom.server.utils.buffer.BufferWrapper;
|
import net.minestom.server.utils.buffer.BufferWrapper;
|
||||||
import net.minestom.server.utils.item.NbtReaderUtils;
|
import org.jglrxavpok.hephaistos.nbt.*;
|
||||||
import net.minestom.server.utils.nbt.NBT;
|
import org.slf4j.Logger;
|
||||||
import net.minestom.server.utils.nbt.NbtWriter;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class Utils {
|
public class Utils {
|
||||||
|
|
||||||
|
private final static Logger LOGGER = LoggerFactory.getLogger(Utils.class);
|
||||||
|
|
||||||
public static int getVarIntSize(int input) {
|
public static int getVarIntSize(int input) {
|
||||||
return (input & 0xFFFFFF80) == 0
|
return (input & 0xFFFFFF80) == 0
|
||||||
? 1 : (input & 0xFFFFC000) == 0
|
? 1 : (input & 0xFFFFC000) == 0
|
||||||
@ -110,18 +117,18 @@ public class Utils {
|
|||||||
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 void writeEnchant(NbtWriter writer, String listName, Map<Enchantment, Short> enchantmentMap) {
|
private static void writeEnchant(NBTCompound nbt, String listName, Map<Enchantment, Short> enchantmentMap) {
|
||||||
writer.writeList(listName, NBT.NBT_COMPOUND, enchantmentMap.size(), () -> {
|
NBTList<NBTCompound> enchantList = new NBTList<>(NBTTypes.TAG_Compound);
|
||||||
for (Map.Entry<Enchantment, Short> entry : enchantmentMap.entrySet()) {
|
for (Map.Entry<Enchantment, Short> entry : enchantmentMap.entrySet()) {
|
||||||
Enchantment enchantment = entry.getKey();
|
Enchantment enchantment = entry.getKey();
|
||||||
short level = entry.getValue();
|
short level = entry.getValue();
|
||||||
|
|
||||||
writer.writeShort("lvl", level);
|
enchantList.add(new NBTCompound()
|
||||||
|
.setShort("lvl", level)
|
||||||
writer.writeString("id", "minecraft:" + enchantment.name().toLowerCase());
|
.setString("id", "minecraft:" + enchantment.name().toLowerCase())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
nbt.set(listName, enchantList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ItemStack readItemStack(PacketReader reader) {
|
public static ItemStack readItemStack(PacketReader reader) {
|
||||||
@ -141,18 +148,91 @@ public class Utils {
|
|||||||
|
|
||||||
ItemStack item = new ItemStack((short) id, count);
|
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) {
|
if(nbt.containsKey("Enchantments")) {
|
||||||
return item;
|
loadEnchantments(nbt.getList("Enchantments"), item::setEnchantment);
|
||||||
} else if (nbt == 0x0A) {
|
}
|
||||||
reader.readShort(); // Ignored, should be empty (main compound name)
|
if(nbt.containsKey("StoredEnchantments")) {
|
||||||
NbtReaderUtils.readItemStackNBT(reader, item);
|
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;
|
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) {
|
public static void writeBlocks(BufferWrapper buffer, short[] blocksId, int bitsPerEntry) {
|
||||||
short count = 0;
|
short count = 0;
|
||||||
for (short id : blocksId)
|
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) {
|
public static void writeItemStack(PacketWriter packet, ItemStack itemStack) {
|
||||||
if (itemStack == null || itemStack.isAir()) {
|
if (itemStack == null || itemStack.isAir()) {
|
||||||
packet.writeBoolean(false);
|
packet.writeBoolean(false);
|
||||||
@ -209,126 +267,116 @@ public class Utils {
|
|||||||
packet.writeByte(itemStack.getAmount());
|
packet.writeByte(itemStack.getAmount());
|
||||||
|
|
||||||
if (!itemStack.hasNbtTag()) {
|
if (!itemStack.hasNbtTag()) {
|
||||||
packet.writeByte((byte) 0x00); // No nbt
|
packet.writeByte((byte) NBTTypes.TAG_End); // No nbt
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NbtWriter mainWriter = new NbtWriter(packet);
|
NBTCompound itemNBT = new NBTCompound();
|
||||||
|
|
||||||
mainWriter.writeCompound("", writer -> {
|
// Unbreakable
|
||||||
// Unbreakable
|
if (itemStack.isUnbreakable()) {
|
||||||
if (itemStack.isUnbreakable()) {
|
itemNBT.setInt("Unbreakable", 1);
|
||||||
writer.writeInt("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
|
if (hasLore) {
|
||||||
{
|
final ArrayList<ColoredText> lore = itemStack.getLore();
|
||||||
writer.writeShort("Damage", itemStack.getDamage());
|
|
||||||
}
|
|
||||||
// End damage
|
|
||||||
|
|
||||||
// Display
|
final NBTList<NBTString> loreNBT = new NBTList<>(NBTTypes.TAG_String);
|
||||||
boolean hasDisplayName = itemStack.hasDisplayName();
|
for (ColoredText line : lore) {
|
||||||
boolean hasLore = itemStack.hasLore();
|
loreNBT.add(new NBTString(line.toString()));
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
displayNBT.set("Lore", loreNBT);
|
||||||
|
}
|
||||||
|
|
||||||
Map<Enchantment, Short> storedEnchantmentMap = itemStack.getStoredEnchantmentMap();
|
itemNBT.set("display", displayNBT);
|
||||||
if (!storedEnchantmentMap.isEmpty()) {
|
}
|
||||||
writeEnchant(writer, "StoredEnchantments", storedEnchantmentMap);
|
// 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
|
// Start hide flags
|
||||||
{
|
{
|
||||||
List<ItemAttribute> itemAttributes = itemStack.getAttributes();
|
int hideFlag = itemStack.getHideFlag();
|
||||||
if (!itemAttributes.isEmpty()) {
|
if (hideFlag != 0) {
|
||||||
packet.writeByte((byte) 0x09); // Type id (list)
|
itemNBT.setInt("HideFlags", hideFlag);
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// End attribute
|
}
|
||||||
|
// End hide flags
|
||||||
|
|
||||||
// Start potion
|
// Start custom model data
|
||||||
{
|
{
|
||||||
Set<PotionType> potionTypes = itemStack.getPotionTypes();
|
int customModelData = itemStack.getCustomModelData();
|
||||||
if (!potionTypes.isEmpty()) {
|
if (customModelData != 0) {
|
||||||
for (PotionType potionType : potionTypes) {
|
itemNBT.setInt("CustomModelData", customModelData);
|
||||||
packet.writeByte((byte) 0x08); // type id (string)
|
|
||||||
packet.writeShortSizedString("Potion");
|
|
||||||
packet.writeShortSizedString("minecraft:" + potionType.name().toLowerCase());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// End potion
|
}
|
||||||
|
// End custom model data
|
||||||
// Start hide flags
|
packet.writeNBT("", itemNBT);
|
||||||
{
|
|
||||||
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
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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