diff --git a/build.gradle b/build.gradle index ac0e56ca3..a8588881c 100644 --- a/build.gradle +++ b/build.gradle @@ -140,7 +140,7 @@ dependencies { api 'org.apache.logging.log4j:log4j-slf4j-impl:2.14.0' // Guava 21.0+ required for Mixin, but Authlib imports 17.0 - api 'com.google.guava:guava:21.0' + api 'com.google.guava:guava:30.1-jre' api 'com.mojang:authlib:1.5.21' // Code modification diff --git a/src/main/java/net/minestom/server/data/type/InventoryData.java b/src/main/java/net/minestom/server/data/type/InventoryData.java index c301f4b8f..f8df92439 100644 --- a/src/main/java/net/minestom/server/data/type/InventoryData.java +++ b/src/main/java/net/minestom/server/data/type/InventoryData.java @@ -35,7 +35,7 @@ public class InventoryData extends DataType { // Read all item stacks for (int i = 0; i < size; i++) { - inventory.setItemStack(i, reader.readSlot()); + inventory.setItemStack(i, reader.readItemStack()); } return inventory; diff --git a/src/main/java/net/minestom/server/data/type/ItemStackData.java b/src/main/java/net/minestom/server/data/type/ItemStackData.java index 810be1e98..efbc7454b 100644 --- a/src/main/java/net/minestom/server/data/type/ItemStackData.java +++ b/src/main/java/net/minestom/server/data/type/ItemStackData.java @@ -15,6 +15,6 @@ public class ItemStackData extends DataType { @NotNull @Override public ItemStack decode(@NotNull BinaryReader reader) { - return reader.readSlot(); + return reader.readItemStack(); } } diff --git a/src/main/java/net/minestom/server/data/type/array/ItemStackArrayData.java b/src/main/java/net/minestom/server/data/type/array/ItemStackArrayData.java index d88dd75a7..86f129457 100644 --- a/src/main/java/net/minestom/server/data/type/array/ItemStackArrayData.java +++ b/src/main/java/net/minestom/server/data/type/array/ItemStackArrayData.java @@ -20,7 +20,7 @@ public class ItemStackArrayData extends DataType { public ItemStack[] decode(@NotNull BinaryReader reader) { ItemStack[] items = new ItemStack[reader.readVarInt()]; for (int i = 0; i < items.length; i++) { - items[i] = reader.readSlot(); + items[i] = reader.readItemStack(); } return items; } diff --git a/src/main/java/net/minestom/server/gamedata/tags/Tag.java b/src/main/java/net/minestom/server/gamedata/tags/Tag.java index 8b052d92e..5513f0609 100644 --- a/src/main/java/net/minestom/server/gamedata/tags/Tag.java +++ b/src/main/java/net/minestom/server/gamedata/tags/Tag.java @@ -19,7 +19,7 @@ public class Tag { private Set values; /** - * Creates a new empty tag + * Creates a new empty tag. This does not cache the tag. */ public Tag(NamespaceID name) { this.name = name; @@ -27,6 +27,15 @@ public class Tag { lockValues(); } + /** + * Creates a new tag with the given values. This does not cache the tag. + */ + public Tag(NamespaceID name, Set values) { + this.name = name; + this.values = new HashSet<>(values); + lockValues(); + } + /** * Creates a new tag with the contents of the container * @param manager Used to load tag contents (as tags are valid values inside 'values') diff --git a/src/main/java/net/minestom/server/network/packet/client/ClientPacket.java b/src/main/java/net/minestom/server/network/packet/client/ClientPacket.java index 43bcdd328..9716e3d61 100644 --- a/src/main/java/net/minestom/server/network/packet/client/ClientPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/ClientPacket.java @@ -1,10 +1,18 @@ package net.minestom.server.network.packet.client; +import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.binary.Readable; +import net.minestom.server.utils.binary.Writeable; +import org.jetbrains.annotations.NotNull; /** * Represents a packet received from a client. */ -public interface ClientPacket extends Readable { +public interface ClientPacket extends Readable, Writeable { + @Override + default void write(@NotNull BinaryWriter writer) { + // FIXME: remove when all packets are written and read properly + throw new UnsupportedOperationException("WIP: This packet is not setup to be written from Minestom code at the moment."); + } } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowPacket.java index 877efcaba..12948ece1 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowPacket.java @@ -21,6 +21,6 @@ public class ClientClickWindowPacket extends ClientPlayPacket { this.button = reader.readByte(); this.actionNumber = reader.readShort(); this.mode = reader.readVarInt(); - this.item = reader.readSlot(); + this.item = reader.readItemStack(); } } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientCreativeInventoryActionPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientCreativeInventoryActionPacket.java index 5a3924c55..e1ed4b407 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientCreativeInventoryActionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientCreativeInventoryActionPacket.java @@ -13,6 +13,6 @@ public class ClientCreativeInventoryActionPacket extends ClientPlayPacket { @Override public void read(@NotNull BinaryReader reader) { this.slot = reader.readShort(); - this.item = reader.readSlot(); + this.item = reader.readItemStack(); } } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientEditBookPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientEditBookPacket.java index e43c1830f..1987fa40b 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientEditBookPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientEditBookPacket.java @@ -14,7 +14,7 @@ public class ClientEditBookPacket extends ClientPlayPacket { @Override public void read(@NotNull BinaryReader reader) { - this.book = reader.readSlot(); + this.book = reader.readItemStack(); this.isSigning = reader.readBoolean(); this.hand = Player.Hand.values()[reader.readVarInt()]; } diff --git a/src/main/java/net/minestom/server/network/packet/server/ServerPacket.java b/src/main/java/net/minestom/server/network/packet/server/ServerPacket.java index a4cdb19d5..4c48415cf 100644 --- a/src/main/java/net/minestom/server/network/packet/server/ServerPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/ServerPacket.java @@ -1,21 +1,23 @@ package net.minestom.server.network.packet.server; import net.minestom.server.network.player.PlayerConnection; -import net.minestom.server.utils.binary.BinaryWriter; +import net.minestom.server.utils.binary.BinaryReader; +import net.minestom.server.utils.binary.Readable; import net.minestom.server.utils.binary.Writeable; import org.jetbrains.annotations.NotNull; +import java.nio.CharBuffer; + /** * Represents a packet which can be sent to a player using {@link PlayerConnection#sendPacket(ServerPacket)}. */ -public interface ServerPacket extends Writeable { +public interface ServerPacket extends Readable, Writeable { - /** - * Writes the packet to a {@link BinaryWriter}. - * - * @param writer the writer to write the packet to. - */ - void write(@NotNull BinaryWriter writer); + @Override + default void read(@NotNull BinaryReader reader) { + // FIXME: remove when all packets are written and read properly + throw new UnsupportedOperationException("WIP: This packet is not set up to be read from Minestom code at the moment."); + } /** * Gets the id of this packet. diff --git a/src/main/java/net/minestom/server/network/packet/server/play/TagsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/TagsPacket.java index 7c6e34c6d..1a67453ad 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/TagsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/TagsPacket.java @@ -1,14 +1,20 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.MinecraftServer; +import net.minestom.server.entity.EntityType; +import net.minestom.server.fluids.Fluid; import net.minestom.server.gamedata.tags.Tag; +import net.minestom.server.instance.block.Block; +import net.minestom.server.item.Material; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.registry.Registries; import net.minestom.server.utils.NamespaceID; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; @@ -27,6 +33,11 @@ public class TagsPacket implements ServerPacket { MinecraftServer.getTagManager().addRequiredTagsToPacket(REQUIRED_TAGS_PACKET); } + /** + * Default constructor, required for reflection operations. + */ + public TagsPacket() {} + @Override public void write(@NotNull BinaryWriter writer) { writeTags(writer, blockTags, name -> Registries.getBlock(name).ordinal()); @@ -35,6 +46,14 @@ public class TagsPacket implements ServerPacket { writeTags(writer, entityTags, name -> Registries.getEntityType(name).ordinal()); } + @Override + public void read(@NotNull BinaryReader reader) { + readTags(reader, blockTags, id -> NamespaceID.from("minecraft", Block.values()[id].getName())); + readTags(reader, itemTags, id -> NamespaceID.from("minecraft", Material.values()[id].getName())); + readTags(reader, fluidTags, id -> NamespaceID.from(Fluid.values()[id].getNamespaceID())); + readTags(reader, entityTags, id -> NamespaceID.from(EntityType.values()[id].getNamespaceID())); + } + private void writeTags(BinaryWriter writer, List tags, Function idSupplier) { writer.writeVarInt(tags.size()); for (Tag tag : tags) { @@ -51,6 +70,23 @@ public class TagsPacket implements ServerPacket { } } + public void readTags(BinaryReader reader, List output, Function idSupplier) { + output.clear(); + int length = reader.readVarInt(); + for (int i = 0; i < length; i++) { + String name = reader.readSizedString(Integer.MAX_VALUE); + + int count = reader.readVarInt(); + Set values = new HashSet<>(); + for (int j = 0; j < count; j++) { + int protocolID = reader.readVarInt(); + values.add(idSupplier.apply(protocolID)); + } + + output.add(new Tag(NamespaceID.from(name), values)); + } + } + @Override public int getId() { return ServerPacketIdentifier.TAGS; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/TimeUpdatePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/TimeUpdatePacket.java index 9b6c98622..5107d9d8d 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/TimeUpdatePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/TimeUpdatePacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; @@ -10,12 +11,23 @@ public class TimeUpdatePacket implements ServerPacket { public long worldAge; public long timeOfDay; + /** + * Default constructor, required for reflection operations. + */ + public TimeUpdatePacket() {} + @Override public void write(@NotNull BinaryWriter writer) { writer.writeLong(worldAge); writer.writeLong(timeOfDay); } + @Override + public void read(@NotNull BinaryReader reader) { + worldAge = reader.readLong(); + timeOfDay = reader.readLong(); + } + @Override public int getId() { return ServerPacketIdentifier.TIME_UPDATE; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/TitlePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/TitlePacket.java index 7820e4adb..b7942cb5e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/TitlePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/TitlePacket.java @@ -6,6 +6,7 @@ import net.minestom.server.network.packet.server.ComponentHoldingServerPacket; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.utils.TickUtils; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import org.apache.commons.lang3.Validate; import org.jetbrains.annotations.NotNull; @@ -67,6 +68,10 @@ public class TitlePacket implements ComponentHoldingServerPacket { this.fadeOut = fadeOut; } + public TitlePacket() { + this(SET_TITLE, Component.empty()); + } + @Override public void write(@NotNull BinaryWriter writer) { writer.writeVarInt(action.ordinal()); @@ -88,6 +93,27 @@ public class TitlePacket implements ComponentHoldingServerPacket { } } + @Override + public void read(@NotNull BinaryReader reader) { + action = Action.values()[reader.readVarInt()]; + switch (action) { + case SET_TITLE: + case SET_SUBTITLE: + case SET_ACTION_BAR: + payload = reader.readComponent(Integer.MAX_VALUE); + break; + + case SET_TIMES_AND_DISPLAY: + fadeIn = reader.readInt(); + stay = reader.readInt(); + fadeOut = reader.readInt(); + + case HIDE: + case RESET: + break; + } + } + @Override public int getId() { return ServerPacketIdentifier.TITLE; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/TradeListPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/TradeListPacket.java index f921563dd..9d559616a 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/TradeListPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/TradeListPacket.java @@ -3,7 +3,10 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.item.ItemStack; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; +import net.minestom.server.utils.binary.Readable; +import net.minestom.server.utils.binary.Writeable; import org.jetbrains.annotations.NotNull; public class TradeListPacket implements ServerPacket { @@ -15,6 +18,13 @@ public class TradeListPacket implements ServerPacket { public boolean regularVillager; public boolean canRestock; + /** + * Default constructor, required for reflection operations. + */ + public TradeListPacket() { + trades = new Trade[0]; + } + @Override public void write(@NotNull BinaryWriter writer) { writer.writeVarInt(windowId); @@ -28,12 +38,28 @@ public class TradeListPacket implements ServerPacket { writer.writeBoolean(canRestock); } + @Override + public void read(@NotNull BinaryReader reader) { + windowId = reader.readVarInt(); + byte tradeCount = reader.readByte(); + + trades = new Trade[tradeCount]; + for (int i = 0; i < tradeCount; i++) { + trades[i] = new Trade(); + trades[i].read(reader); + } + villagerLevel = reader.readVarInt(); + experience = reader.readVarInt(); + regularVillager = reader.readBoolean(); + canRestock = reader.readBoolean(); + } + @Override public int getId() { return ServerPacketIdentifier.TRADE_LIST; } - public static class Trade { + public static class Trade implements Writeable, Readable { public ItemStack inputItem1; public ItemStack result; @@ -46,8 +72,8 @@ public class TradeListPacket implements ServerPacket { public float priceMultiplier; public int demand; - - private void write(BinaryWriter writer) { + @Override + public void write(BinaryWriter writer) { boolean hasSecondItem = inputItem2 != null; writer.writeItemStack(inputItem1); @@ -64,6 +90,26 @@ public class TradeListPacket implements ServerPacket { writer.writeInt(demand); } + @Override + public void read(@NotNull BinaryReader reader) { + inputItem1 = reader.readItemStack(); + result = reader.readItemStack(); + + boolean hasSecondItem = reader.readBoolean(); + if(hasSecondItem) { + inputItem2 = reader.readItemStack(); + } else { + inputItem2 = null; + } + + tradeDisabled = reader.readBoolean(); + tradeUsesNumber = reader.readInt(); + maxTradeUsesNumber = reader.readInt(); + exp = reader.readInt(); + specialPrice = reader.readInt(); + priceMultiplier = reader.readFloat(); + demand = reader.readInt(); + } } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/UnloadChunkPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/UnloadChunkPacket.java index 79e858a5e..638e70781 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/UnloadChunkPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/UnloadChunkPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; @@ -9,12 +10,23 @@ public class UnloadChunkPacket implements ServerPacket { public int chunkX, chunkZ; + /** + * Default constructor, required for reflection operations. + */ + public UnloadChunkPacket() {} + @Override public void write(@NotNull BinaryWriter writer) { writer.writeInt(chunkX); writer.writeInt(chunkZ); } + @Override + public void read(@NotNull BinaryReader reader) { + chunkX = reader.readInt(); + chunkZ = reader.readInt(); + } + @Override public int getId() { return ServerPacketIdentifier.UNLOAD_CHUNK; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/UnlockRecipesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/UnlockRecipesPacket.java index 68f435baa..f43f3cb8a 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/UnlockRecipesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/UnlockRecipesPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; @@ -19,6 +20,14 @@ public class UnlockRecipesPacket implements ServerPacket { // Only if mode = 0 public String[] initRecipesId; + /** + * Default constructor, required for reflection operations. + */ + public UnlockRecipesPacket() { + recipesId = new String[0]; + initRecipesId = new String[0]; + } + @Override public void write(@NotNull BinaryWriter writer) { writer.writeVarInt(mode); @@ -41,6 +50,30 @@ public class UnlockRecipesPacket implements ServerPacket { } } + @Override + public void read(@NotNull BinaryReader reader) { + mode = reader.readVarInt(); + + craftingRecipeBookOpen = reader.readBoolean(); + craftingRecipeBookFilterActive = reader.readBoolean(); + smeltingRecipeBookOpen = reader.readBoolean(); + smeltingRecipeBookFilterActive = reader.readBoolean(); + + int length = reader.readVarInt(); + recipesId = new String[length]; + for (int i = 0; i < length; i++) { + recipesId[i] = reader.readSizedString(Integer.MAX_VALUE); + } + + if(mode == 0) { + int initRecipesLength = reader.readVarInt(); + initRecipesId = new String[initRecipesLength]; + for (int i = 0; i < length; i++) { + initRecipesId[i] = reader.readSizedString(Integer.MAX_VALUE); + } + } + } + @Override public int getId() { return ServerPacketIdentifier.UNLOCK_RECIPES; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/UpdateHealthPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/UpdateHealthPacket.java index 25ccde28a..dc9756872 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/UpdateHealthPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/UpdateHealthPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; @@ -11,6 +12,11 @@ public class UpdateHealthPacket implements ServerPacket { public int food; public float foodSaturation; + /** + * Default constructor, required for reflection operations. + */ + public UpdateHealthPacket() {} + @Override public void write(@NotNull BinaryWriter writer) { writer.writeFloat(health); @@ -18,6 +24,13 @@ public class UpdateHealthPacket implements ServerPacket { writer.writeFloat(foodSaturation); } + @Override + public void read(@NotNull BinaryReader reader) { + health = reader.readFloat(); + food = reader.readVarInt(); + foodSaturation = reader.readFloat(); + } + @Override public int getId() { return ServerPacketIdentifier.UPDATE_HEALTH; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/UpdateLightPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/UpdateLightPacket.java index cb1d23aa8..55ff304be 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/UpdateLightPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/UpdateLightPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.cache.CacheablePacket; import net.minestom.server.utils.cache.TemporaryCache; @@ -9,6 +10,8 @@ import net.minestom.server.utils.cache.TimedBuffer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -36,9 +39,25 @@ public class UpdateLightPacket implements ServerPacket, CacheablePacket { private final UUID identifier; private final long timestamp; + /** + * Default constructor, required for reflection operations. + * This one will make a packet that is not meant to be cached + */ + public UpdateLightPacket() { + this(UUID.randomUUID(), Long.MAX_VALUE); + for (int i = 0; i < 14; i++) { + skyLight.add(new byte[2048]); + } + for (int i = 0; i < 6; i++) { + blockLight.add(new byte[2048]); + } + } + public UpdateLightPacket(@Nullable UUID identifier, long timestamp) { this.identifier = identifier; this.timestamp = timestamp; + skyLight = new ArrayList<>(14); + blockLight = new ArrayList<>(6); } @Override @@ -67,6 +86,44 @@ public class UpdateLightPacket implements ServerPacket, CacheablePacket { } } + @Override + public void read(@NotNull BinaryReader reader) { + chunkX = reader.readVarInt(); + chunkZ = reader.readVarInt(); + + trustEdges = reader.readBoolean(); + + skyLightMask = reader.readVarInt(); + blockLightMask = reader.readVarInt(); + + emptySkyLightMask = reader.readVarInt(); + emptyBlockLightMask = reader.readVarInt(); + + // sky light + skyLight.clear(); + for (int i = 0; i < 14; i++) { + int length = reader.readVarInt(); + if(length != 2048) { + throw new IllegalStateException("Length must be 2048."); + } + + byte[] bytes = reader.readBytes(length); + skyLight.add(bytes); + } + + // block light + blockLight.clear(); + for (int i = 0; i < 6; i++) { + int length = reader.readVarInt(); + if(length != 2048) { + throw new IllegalStateException("Length must be 2048."); + } + + byte[] bytes = reader.readBytes(length); + blockLight.add(bytes); + } + } + @Override public int getId() { return ServerPacketIdentifier.UPDATE_LIGHT; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/UpdateScorePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/UpdateScorePacket.java index 2140e37a0..7b5c3a619 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/UpdateScorePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/UpdateScorePacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; @@ -12,6 +13,14 @@ public class UpdateScorePacket implements ServerPacket { public String objectiveName; public int value; + /** + * Default constructor, required for reflection operations. + */ + public UpdateScorePacket() { + entityName = ""; + objectiveName = ""; + } + @Override public void write(@NotNull BinaryWriter writer) { writer.writeSizedString(entityName); @@ -22,6 +31,16 @@ public class UpdateScorePacket implements ServerPacket { } } + @Override + public void read(@NotNull BinaryReader reader) { + entityName = reader.readSizedString(Integer.MAX_VALUE); + action = reader.readByte(); + objectiveName = reader.readSizedString(Integer.MAX_VALUE); + if(action != 1) { + value = reader.readVarInt(); + } + } + @Override public int getId() { return ServerPacketIdentifier.UPDATE_SCORE; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/UpdateViewDistancePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/UpdateViewDistancePacket.java index 4bb24a7db..23ac1a004 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/UpdateViewDistancePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/UpdateViewDistancePacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; @@ -9,11 +10,21 @@ public class UpdateViewDistancePacket implements ServerPacket { public int viewDistance; + /** + * Default constructor, required for reflection operations. + */ + public UpdateViewDistancePacket() {} + @Override public void write(@NotNull BinaryWriter writer) { writer.writeVarInt(viewDistance); } + @Override + public void read(@NotNull BinaryReader reader) { + viewDistance = reader.readVarInt(); + } + @Override public int getId() { return ServerPacketIdentifier.UPDATE_VIEW_DISTANCE; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/UpdateViewPositionPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/UpdateViewPositionPacket.java index 14204bac5..48d2814c5 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/UpdateViewPositionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/UpdateViewPositionPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; @@ -9,12 +10,23 @@ public class UpdateViewPositionPacket implements ServerPacket { public int chunkX, chunkZ; + /** + * Default constructor, required for reflection operations. + */ + public UpdateViewPositionPacket() {} + @Override public void write(@NotNull BinaryWriter writer) { writer.writeVarInt(chunkX); writer.writeVarInt(chunkZ); } + @Override + public void read(@NotNull BinaryReader reader) { + chunkX = reader.readVarInt(); + chunkZ = reader.readVarInt(); + } + @Override public int getId() { return ServerPacketIdentifier.UPDATE_VIEW_POSITION; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/VehicleMovePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/VehicleMovePacket.java index 4b886ac1b..1a53d5abf 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/VehicleMovePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/VehicleMovePacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; @@ -10,6 +11,11 @@ public class VehicleMovePacket implements ServerPacket { public double x, y, z; public float yaw, pitch; + /** + * Default constructor, required for reflection operations. + */ + public VehicleMovePacket() {} + @Override public void write(@NotNull BinaryWriter writer) { writer.writeDouble(x); @@ -19,6 +25,15 @@ public class VehicleMovePacket implements ServerPacket { writer.writeFloat(pitch); } + @Override + public void read(@NotNull BinaryReader reader) { + x = reader.readDouble(); + y = reader.readDouble(); + z = reader.readDouble(); + yaw = reader.readFloat(); + pitch = reader.readFloat(); + } + @Override public int getId() { return ServerPacketIdentifier.VEHICLE_MOVE; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/WindowConfirmationPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/WindowConfirmationPacket.java index 5bad0d5bc..54fd0da47 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/WindowConfirmationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/WindowConfirmationPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; @@ -11,6 +12,11 @@ public class WindowConfirmationPacket implements ServerPacket { public short actionNumber; public boolean accepted; + /** + * Default constructor, required for reflection operations. + */ + public WindowConfirmationPacket() {} + @Override public void write(@NotNull BinaryWriter writer) { writer.writeByte(windowId); @@ -18,6 +24,13 @@ public class WindowConfirmationPacket implements ServerPacket { writer.writeBoolean(accepted); } + @Override + public void read(@NotNull BinaryReader reader) { + windowId = reader.readByte(); + actionNumber = reader.readShort(); + accepted = reader.readBoolean(); + } + @Override public int getId() { return ServerPacketIdentifier.WINDOW_CONFIRMATION; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/WindowItemsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/WindowItemsPacket.java index 4ba690fd1..eff759117 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/WindowItemsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/WindowItemsPacket.java @@ -3,6 +3,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.item.ItemStack; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; @@ -11,6 +12,11 @@ public class WindowItemsPacket implements ServerPacket { public byte windowId; public ItemStack[] items; + /** + * Default constructor, required for reflection operations. + */ + public WindowItemsPacket() {} + @Override public void write(@NotNull BinaryWriter writer) { writer.writeByte(windowId); @@ -26,6 +32,17 @@ public class WindowItemsPacket implements ServerPacket { } } + @Override + public void read(@NotNull BinaryReader reader) { + windowId = reader.readByte(); + + short length = reader.readShort(); + items = new ItemStack[length]; + for (int i = 0; i < length; i++) { + items[i] = reader.readItemStack(); + } + } + @Override public int getId() { return ServerPacketIdentifier.WINDOW_ITEMS; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/WindowPropertyPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/WindowPropertyPacket.java index 261ed1db8..28a724f49 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/WindowPropertyPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/WindowPropertyPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; @@ -11,6 +12,11 @@ public class WindowPropertyPacket implements ServerPacket { public short property; public short value; + /** + * Default constructor, required for reflection operations. + */ + public WindowPropertyPacket() {} + @Override public void write(@NotNull BinaryWriter writer) { writer.writeByte(windowId); @@ -18,6 +24,13 @@ public class WindowPropertyPacket implements ServerPacket { writer.writeShort(value); } + @Override + public void read(@NotNull BinaryReader reader) { + windowId = reader.readByte(); + property = reader.readShort(); + value = reader.readShort(); + } + @Override public int getId() { return ServerPacketIdentifier.WINDOW_PROPERTY; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderPacket.java index 059110667..73b02120d 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderPacket.java @@ -10,6 +10,16 @@ public class WorldBorderPacket implements ServerPacket { public Action action; public WBAction wbAction; + private static final WBAction DEFAULT_ACTION = new WBSetSize(0.0); + + /** + * Default constructor, required for reflection operations. + */ + public WorldBorderPacket() { + action = Action.SET_SIZE; + wbAction = DEFAULT_ACTION; + } + @Override public void write(@NotNull BinaryWriter writer) { writer.writeVarInt(action.ordinal()); diff --git a/src/main/java/net/minestom/server/network/packet/server/status/PongPacket.java b/src/main/java/net/minestom/server/network/packet/server/status/PongPacket.java index 4d0df60a2..b088e9842 100644 --- a/src/main/java/net/minestom/server/network/packet/server/status/PongPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/status/PongPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.status; import net.minestom.server.network.packet.server.ServerPacket; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; @@ -8,6 +9,11 @@ public class PongPacket implements ServerPacket { public long number; + /** + * Default constructor, required for reflection operations. + */ + public PongPacket() {} + public PongPacket(long number) { this.number = number; } @@ -17,6 +23,11 @@ public class PongPacket implements ServerPacket { writer.writeLong(number); } + @Override + public void read(@NotNull BinaryReader reader) { + number = reader.readLong(); + } + @Override public int getId() { return 0x01; diff --git a/src/main/java/net/minestom/server/utils/binary/BinaryReader.java b/src/main/java/net/minestom/server/utils/binary/BinaryReader.java index 7e9b7ef13..3bf6ca0c6 100644 --- a/src/main/java/net/minestom/server/utils/binary/BinaryReader.java +++ b/src/main/java/net/minestom/server/utils/binary/BinaryReader.java @@ -63,10 +63,20 @@ public class BinaryReader extends InputStream { return buffer.readUnsignedShort(); } + /** + * Same as readInt + */ public int readInteger() { return buffer.readInt(); } + /** + * Same as readInteger, created for parity with BinaryWriter + */ + public int readInt() { + return buffer.readInt(); + } + public long readLong() { return buffer.readLong(); } @@ -143,12 +153,20 @@ public class BinaryReader extends InputStream { * @return the read item * @throws NullPointerException if the item could not get read */ - public ItemStack readSlot() { + public ItemStack readItemStack() { final ItemStack itemStack = NBTUtils.readItemStack(this); Check.notNull(itemStack, "#readSlot returned null, probably because the buffer was corrupted"); return itemStack; } + /** + * Same as readItemStack + */ + @Deprecated + public ItemStack readSlot() { + return readItemStack(); + } + /** * Use {@link #readComponent(int)} */ diff --git a/src/test/java/readwritepackets/ReadWritePackets.java b/src/test/java/readwritepackets/ReadWritePackets.java new file mode 100644 index 000000000..e29a05ec5 --- /dev/null +++ b/src/test/java/readwritepackets/ReadWritePackets.java @@ -0,0 +1,86 @@ +package readwritepackets; + +import com.google.common.reflect.ClassPath; +import net.minestom.server.MinecraftServer; +import net.minestom.server.network.packet.client.ClientPacket; +import net.minestom.server.network.packet.server.ServerPacket; +import net.minestom.server.utils.binary.BinaryReader; +import net.minestom.server.utils.binary.BinaryWriter; +import net.minestom.server.utils.binary.Readable; +import net.minestom.server.utils.binary.Writeable; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +/** + * If you are using IntelliJ, set it up so that tests are run through IntelliJ and not Gradle for this collection of tests + */ +public class ReadWritePackets { + + /** + * Test that all read operations on ServerPacket subclasses are implemented, and use the correct amount of memory. + * This is by no means a perfect test as some packets have variable length and content has to be validated + */ + @TestFactory + public Collection checkServerImplementationPresence() throws IOException { + return checkImplementationPresence(ServerPacket.class); + } + + /** + * Test that all write operations on ClientPacket subclasses are implemented, and use the correct amount of memory. + * This is by no means a perfect test as some packets have variable length and content has to be validated + */ + @TestFactory + public Collection checkClientImplementationPresence() throws IOException { + return checkImplementationPresence(ClientPacket.class); + } + + private Collection checkImplementationPresence(Class packetClass) throws IOException { + ClassPath cp = ClassPath.from(ClassLoader.getSystemClassLoader()); + List allTests = new LinkedList<>(); + for(ClassPath.ClassInfo classInfo : cp.getAllClasses()) { + if(!classInfo.getPackageName().startsWith("net.minestom.server.network.packet")) + continue; + try { + Class clazz = classInfo.load(); + if(packetClass.isAssignableFrom(clazz) && !clazz.isInterface() && ((clazz.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT)) { + allTests.add(DynamicTest.dynamicTest("WriteThenRead "+clazz.getSimpleName(), () -> { + // required for managers to be loaded + MinecraftServer.init(); + + BinaryWriter writer = new BinaryWriter(); + T packet = (T) clazz.getConstructor().newInstance(); + + // write packet + packet.write(writer); + + // re-read packet + byte[] originalBytes = writer.toByteArray(); + BinaryReader reader = new BinaryReader(originalBytes); + packet.read(reader); + + Assertions.assertEquals(0, reader.getRemainingBytes().length, "Packet did not read all available data"); + + // re-write to ensure packet contents are the same + BinaryWriter secondWriter = new BinaryWriter(); + packet.write(secondWriter); + + // check that contents are the same than before read + Assertions.assertArrayEquals(originalBytes, secondWriter.toByteArray()); + })); + } + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + return allTests; + } +}